diff options
Diffstat (limited to 'src/test')
104 files changed, 8930 insertions, 3339 deletions
diff --git a/src/test/test-acl-util.c b/src/test/test-acl-util.c new file mode 100644 index 0000000000..5b572bb0bf --- /dev/null +++ b/src/test/test-acl-util.c @@ -0,0 +1,85 @@ +/*** + 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 <fcntl.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "acl-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "string-util.h" +#include "user-util.h" + +static void test_add_acls_for_user(void) { + char fn[] = "/tmp/test-empty.XXXXXX"; + _cleanup_close_ int fd = -1; + char *cmd; + uid_t uid; + int r; + + fd = mkostemp_safe(fn); + assert_se(fd >= 0); + + /* Use the mode that user journal files use */ + assert_se(fchmod(fd, 0640) == 0); + + cmd = strjoina("ls -l ", fn); + assert_se(system(cmd) == 0); + + cmd = strjoina("getfacl -p ", fn); + assert_se(system(cmd) == 0); + + if (getuid() == 0) { + const char *nobody = "nobody"; + r = get_user_creds(&nobody, &uid, NULL, NULL, NULL); + if (r < 0) + uid = 0; + } else + uid = getuid(); + + r = add_acls_for_user(fd, uid); + assert_se(r >= 0); + + cmd = strjoina("ls -l ", fn); + assert_se(system(cmd) == 0); + + cmd = strjoina("getfacl -p ", fn); + assert_se(system(cmd) == 0); + + /* set the acls again */ + + r = add_acls_for_user(fd, uid); + assert_se(r >= 0); + + cmd = strjoina("ls -l ", fn); + assert_se(system(cmd) == 0); + + cmd = strjoina("getfacl -p ", fn); + assert_se(system(cmd) == 0); + + unlink(fn); +} + +int main(int argc, char **argv) { + test_add_acls_for_user(); + + return 0; +} diff --git a/src/test/test-af-list.c b/src/test/test-af-list.c new file mode 100644 index 0000000000..aeaa0929b1 --- /dev/null +++ b/src/test/test-af-list.c @@ -0,0 +1,49 @@ +/*** + This file is part of systemd + + Copyright 2015 Daniel Mack + + 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 <string.h> +#include <sys/socket.h> + +#include "macro.h" +#include "string-util.h" +#include "util.h" + +static const struct af_name* lookup_af(register const char *str, register unsigned int len); + +#include "af-from-name.h" +#include "af-list.h" +#include "af-to-name.h" + +int main(int argc, const char *argv[]) { + + unsigned int i; + + for (i = 0; i < ELEMENTSOF(af_names); i++) { + if (af_names[i]) { + assert_se(streq(af_to_name(i), af_names[i])); + assert_se(af_from_name(af_names[i]) == (int) i); + } + } + + assert_se(af_to_name(af_max()) == NULL); + assert_se(af_to_name(-1) == NULL); + assert_se(af_from_name("huddlduddl") == AF_UNSPEC); + + return 0; +} diff --git a/src/test/test-alloc-util.c b/src/test/test-alloc-util.c new file mode 100644 index 0000000000..cc4821eaf5 --- /dev/null +++ b/src/test/test-alloc-util.c @@ -0,0 +1,55 @@ +/*** + This file is part of systemd. + + Copyright 2010 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 "alloc-util.h" +#include "macro.h" +#include "util.h" + +static void test_alloca(void) { + static const uint8_t zero[997] = { }; + char *t; + + t = alloca_align(17, 512); + assert_se(!((uintptr_t)t & 0xff)); + memzero(t, 17); + + t = alloca0_align(997, 1024); + assert_se(!((uintptr_t)t & 0x1ff)); + assert_se(!memcmp(t, zero, 997)); +} + +static void test_memdup_multiply(void) { + int org[] = {1, 2, 3}; + int *dup; + + dup = (int*)memdup_multiply(org, sizeof(int), 3); + + assert_se(dup); + assert_se(dup[0] == 1); + assert_se(dup[1] == 2); + assert_se(dup[2] == 3); + free(dup); +} + +int main(int argc, char *argv[]) { + test_alloca(); + test_memdup_multiply(); + + return 0; +} diff --git a/src/test/test-architecture.c b/src/test/test-architecture.c index 30bdec45e5..f41e488d99 100644 --- a/src/test/test-architecture.c +++ b/src/test/test-architecture.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,24 +17,24 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "virt.h" #include "architecture.h" -#include "util.h" #include "log.h" +#include "util.h" +#include "virt.h" int main(int argc, char *argv[]) { - const char *id = NULL; int a, v; - v = detect_virtualization(&id); + v = detect_virtualization(); if (v == -EPERM || v == -EACCES) return EXIT_TEST_SKIP; assert_se(v >= 0); log_info("virtualization=%s id=%s", - v == VIRTUALIZATION_CONTAINER ? "container" : v == VIRTUALIZATION_VM ? "vm" : "n/a", - strna(id)); + VIRTUALIZATION_IS_CONTAINER(v) ? "container" : + VIRTUALIZATION_IS_VM(v) ? "vm" : "n/a", + virtualization_to_string(v)); a = uname_architecture(); assert_se(a >= 0); diff --git a/src/test/test-arphrd-list.c b/src/test/test-arphrd-list.c new file mode 100644 index 0000000000..f3989ad201 --- /dev/null +++ b/src/test/test-arphrd-list.c @@ -0,0 +1,49 @@ +/*** + This file is part of systemd + + Copyright 2015 Daniel Mack + + 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 <net/if_arp.h> +#include <string.h> + +#include "macro.h" +#include "string-util.h" +#include "util.h" + +static const struct arphrd_name* lookup_arphrd(register const char *str, register unsigned int len); + +#include "arphrd-from-name.h" +#include "arphrd-list.h" +#include "arphrd-to-name.h" + +int main(int argc, const char *argv[]) { + + unsigned int i; + + for (i = 1; i < ELEMENTSOF(arphrd_names); i++) { + if (arphrd_names[i]) { + assert_se(streq(arphrd_to_name(i), arphrd_names[i])); + assert_se(arphrd_from_name(arphrd_names[i]) == (int) i); + } + } + + assert_se(arphrd_to_name(arphrd_max()) == NULL); + assert_se(arphrd_to_name(0) == NULL); + assert_se(arphrd_from_name("huddlduddl") == 0); + + return 0; +} diff --git a/src/test/test-ask-password-api.c b/src/test/test-ask-password-api.c new file mode 100644 index 0000000000..86666597c7 --- /dev/null +++ b/src/test/test-ask-password-api.c @@ -0,0 +1,38 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 "alloc-util.h" +#include "ask-password-api.h" +#include "log.h" + +static void ask_password(void) { + int r; + _cleanup_free_ char *ret; + + r = ask_password_tty("hello?", "da key", 0, 0, NULL, &ret); + assert(r >= 0); + + log_info("Got %s", ret); +} + +int main(int argc, char **argv) { + log_parse_environment(); + + ask_password(); +} diff --git a/src/test/test-async.c b/src/test/test-async.c index abd36d693c..4ebc27f0bd 100644 --- a/src/test/test-async.c +++ b/src/test/test-async.c @@ -20,8 +20,9 @@ #include <unistd.h> #include "async.h" -#include "util.h" +#include "fileio.h" #include "macro.h" +#include "util.h" static bool test_async = false; @@ -35,7 +36,7 @@ int main(int argc, char *argv[]) { int fd; char name[] = "/tmp/test-asynchronous_close.XXXXXX"; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); asynchronous_close(fd); diff --git a/src/test/test-barrier.c b/src/test/test-barrier.c index f37cb49c85..e6aa3b5cfe 100644 --- a/src/test/test-barrier.c +++ b/src/test/test-barrier.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-bitmap.c b/src/test/test-bitmap.c index 96deeded7e..ff22117745 100644 --- a/src/test/test-bitmap.c +++ b/src/test/test-bitmap.c @@ -20,7 +20,7 @@ #include "bitmap.h" int main(int argc, const char *argv[]) { - _cleanup_bitmap_free_ Bitmap *b = NULL; + _cleanup_bitmap_free_ Bitmap *b = NULL, *b2 = NULL; Iterator it; unsigned n = (unsigned) -1, i = 0; @@ -101,5 +101,23 @@ int main(int argc, const char *argv[]) { assert_se(bitmap_set(b, (unsigned) -1) == -ERANGE); + bitmap_free(b); + b = NULL; + assert_se(bitmap_ensure_allocated(&b) == 0); + assert_se(bitmap_ensure_allocated(&b2) == 0); + + assert_se(bitmap_equal(b, b2)); + assert_se(bitmap_set(b, 0) == 0); + bitmap_unset(b, 0); + assert_se(bitmap_equal(b, b2)); + + assert_se(bitmap_set(b, 1) == 0); + bitmap_clear(b); + assert_se(bitmap_equal(b, b2)); + + assert_se(bitmap_set(b, 0) == 0); + assert_se(bitmap_set(b2, 0) == 0); + assert_se(bitmap_equal(b, b2)); + return 0; } diff --git a/src/test/test-boot-timestamps.c b/src/test/test-boot-timestamps.c index 06d93af533..8e68d6510d 100644 --- a/src/test/test-boot-timestamps.c +++ b/src/test/test-boot-timestamps.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,11 +18,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "log.h" +#include "acpi-fpdt.h" #include "boot-timestamps.h" #include "efivars.h" -#include "acpi-fpdt.h" +#include "log.h" +#include "util.h" static int test_acpi_fpdt(void) { usec_t loader_start; @@ -36,17 +34,18 @@ static int test_acpi_fpdt(void) { r = acpi_get_boot_usec(&loader_start, &loader_exit); if (r < 0) { - if (r != -ENOENT) - log_error_errno(r, "Failed to read ACPI FPDT: %m"); - return r; + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES) || r == -ENODATA; + + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, + r, "Failed to read ACPI FPDT: %m"); + return ok ? 0 : r; } log_info("ACPI FPDT: loader start=%s exit=%s duration=%s", format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC), format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC), format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC)); - - return 0; + return 1; } static int test_efi_loader(void) { @@ -59,33 +58,34 @@ static int test_efi_loader(void) { r = efi_loader_get_boot_usec(&loader_start, &loader_exit); if (r < 0) { - if (r != -ENOENT) - log_error_errno(r, "Failed to read EFI loader data: %m"); - return r; + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES); + + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, + r, "Failed to read EFI loader data: %m"); + return ok ? 0 : r; } log_info("EFI Loader: start=%s exit=%s duration=%s", format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC), format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC), format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC)); - - return 0; + return 1; } -int main(int argc, char* argv[]) { +static int test_boot_timestamps(void) { char s[MAX(FORMAT_TIMESPAN_MAX, FORMAT_TIMESTAMP_MAX)]; int r; dual_timestamp fw, l, k; - test_acpi_fpdt(); - test_efi_loader(); - dual_timestamp_from_monotonic(&k, 0); r = boot_timestamps(NULL, &fw, &l); if (r < 0) { - log_error_errno(r, "Failed to read variables: %m"); - return 1; + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES); + + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, + r, "Failed to read variables: %m"); + return ok ? 0 : r; } log_info("Firmware began %s before kernel.", format_timespan(s, sizeof(s), fw.monotonic, 0)); @@ -93,6 +93,21 @@ int main(int argc, char* argv[]) { log_info("Firmware began %s.", format_timestamp(s, sizeof(s), fw.realtime)); log_info("Loader began %s.", format_timestamp(s, sizeof(s), l.realtime)); log_info("Kernel began %s.", format_timestamp(s, sizeof(s), k.realtime)); + return 1; +} + +int main(int argc, char* argv[]) { + int p, q, r; + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + + p = test_acpi_fpdt(); + assert(p >= 0); + q = test_efi_loader(); + assert(q >= 0); + r = test_boot_timestamps(); + assert(r >= 0); - return 0; + return (p > 0 || q > 0 || r >> 0) ? EXIT_SUCCESS : EXIT_TEST_SKIP; } diff --git a/src/test/test-btrfs.c b/src/test/test-btrfs.c index e4771c9dd7..ce29d88412 100644 --- a/src/test/test-btrfs.c +++ b/src/test/test-btrfs.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,23 +19,26 @@ #include <fcntl.h> -#include "log.h" +#include "btrfs-util.h" +#include "fd-util.h" #include "fileio.h" +#include "log.h" +#include "parse-util.h" +#include "string-util.h" #include "util.h" -#include "btrfs-util.h" int main(int argc, char *argv[]) { + BtrfsQuotaInfo quota; int r, 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]; + BtrfsSubvolInfo info; - r = btrfs_subvol_get_info_fd(fd, &info); + r = btrfs_subvol_get_info_fd(fd, 0, &info); if (r < 0) log_error_errno(r, "Failed to get subvolume info: %m"); else { @@ -45,7 +46,7 @@ int main(int argc, char *argv[]) { log_info("read-only (search): %s", yes_no(info.read_only)); } - r = btrfs_subvol_get_quota_fd(fd, "a); + r = btrfs_qgroup_get_quota_fd(fd, 0, "a); if (r < 0) log_error_errno(r, "Failed to get quota info: %m"); else { @@ -80,15 +81,15 @@ int main(int argc, char *argv[]) { if (r < 0) log_error_errno(r, "Failed to make snapshot: %m"); - r = btrfs_subvol_remove("/xxxtest", false); + r = btrfs_subvol_remove("/xxxtest", BTRFS_REMOVE_QUOTA); if (r < 0) log_error_errno(r, "Failed to remove subvolume: %m"); - r = btrfs_subvol_remove("/xxxtest2", false); + r = btrfs_subvol_remove("/xxxtest2", BTRFS_REMOVE_QUOTA); if (r < 0) log_error_errno(r, "Failed to remove subvolume: %m"); - r = btrfs_subvol_remove("/xxxtest3", false); + r = btrfs_subvol_remove("/xxxtest3", BTRFS_REMOVE_QUOTA); if (r < 0) log_error_errno(r, "Failed to remove subvolume: %m"); @@ -96,7 +97,7 @@ int main(int argc, char *argv[]) { if (r < 0) log_error_errno(r, "Failed to make snapshot: %m"); - r = btrfs_subvol_remove("/etc2", false); + r = btrfs_subvol_remove("/etc2", BTRFS_REMOVE_QUOTA); if (r < 0) log_error_errno(r, "Failed to remove subvolume: %m"); @@ -137,13 +138,61 @@ int main(int argc, char *argv[]) { if (r < 0) log_error_errno(r, "Failed to snapshot subvolume: %m"); - r = btrfs_subvol_remove("/xxxrectest", true); + r = btrfs_subvol_remove("/xxxrectest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE); if (r < 0) log_error_errno(r, "Failed to recursively remove subvolume: %m"); - r = btrfs_subvol_remove("/xxxrectest2", true); + r = btrfs_subvol_remove("/xxxrectest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE); if (r < 0) log_error_errno(r, "Failed to recursively remove subvolume: %m"); + r = btrfs_subvol_make("/xxxquotatest"); + if (r < 0) + log_error_errno(r, "Failed to make subvolume: %m"); + + r = btrfs_subvol_auto_qgroup("/xxxquotatest", 0, true); + if (r < 0) + log_error_errno(r, "Failed to set up auto qgroup: %m"); + + r = btrfs_subvol_make("/xxxquotatest/beneath"); + if (r < 0) + log_error_errno(r, "Failed to make subvolume: %m"); + + r = btrfs_subvol_auto_qgroup("/xxxquotatest/beneath", 0, false); + if (r < 0) + log_error_errno(r, "Failed to set up auto qgroup: %m"); + + r = btrfs_qgroup_set_limit("/xxxquotatest/beneath", 0, 4ULL * 1024 * 1024 * 1024); + if (r < 0) + log_error_errno(r, "Failed to set up quota limit: %m"); + + r = btrfs_subvol_set_subtree_quota_limit("/xxxquotatest", 0, 5ULL * 1024 * 1024 * 1024); + if (r < 0) + log_error_errno(r, "Failed to set up quota limit: %m"); + + r = btrfs_subvol_snapshot("/xxxquotatest", "/xxxquotatest2", BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA); + if (r < 0) + log_error_errno(r, "Failed to setup snapshot: %m"); + + r = btrfs_qgroup_get_quota("/xxxquotatest2/beneath", 0, "a); + if (r < 0) + log_error_errno(r, "Failed to query quota: %m"); + + assert_se(quota.referenced_max == 4ULL * 1024 * 1024 * 1024); + + r = btrfs_subvol_get_subtree_quota("/xxxquotatest2", 0, "a); + if (r < 0) + log_error_errno(r, "Failed to query quota: %m"); + + assert_se(quota.referenced_max == 5ULL * 1024 * 1024 * 1024); + + r = btrfs_subvol_remove("/xxxquotatest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE); + if (r < 0) + log_error_errno(r, "Failed remove subvolume: %m"); + + r = btrfs_subvol_remove("/xxxquotatest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE); + if (r < 0) + log_error_errno(r, "Failed remove subvolume: %m"); + return 0; } diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index 87e1da1258..57d9da4855 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,7 +19,9 @@ #include <string.h> +#include "alloc-util.h" #include "calendarspec.h" +#include "string-util.h" #include "util.h" static void test_one(const char *input, const char *output) { @@ -50,15 +50,77 @@ static void test_one(const char *input, const char *output) { assert_se(streq(q, p)); } +static void test_next(const char *input, const char *new_tz, usec_t after, usec_t expect) { + CalendarSpec *c; + usec_t u; + char *old_tz; + char buf[FORMAT_TIMESTAMP_MAX]; + int r; + + old_tz = getenv("TZ"); + if (old_tz) + old_tz = strdupa(old_tz); + + if (new_tz) + assert_se(setenv("TZ", new_tz, 1) >= 0); + else + assert_se(unsetenv("TZ") >= 0); + tzset(); + + assert_se(calendar_spec_from_string(input, &c) >= 0); + + printf("\"%s\"\n", input); + + u = after; + r = calendar_spec_next_usec(c, after, &u); + printf("At: %s\n", r < 0 ? strerror(-r) : format_timestamp_us(buf, sizeof(buf), u)); + if (expect != (usec_t)-1) + assert_se(r >= 0 && u == expect); + else + assert(r == -ENOENT); + + calendar_spec_free(c); + + if (old_tz) + assert_se(setenv("TZ", old_tz, 1) >= 0); + else + assert_se(unsetenv("TZ") >= 0); + tzset(); +} + +static void test_timestamp(void) { + char buf[FORMAT_TIMESTAMP_MAX]; + _cleanup_free_ char *t = NULL; + CalendarSpec *c; + usec_t x, y; + + /* Ensure that a timestamp is also a valid calendar specification. Convert forth and back */ + + x = now(CLOCK_REALTIME); + + assert_se(format_timestamp_us(buf, sizeof(buf), x)); + printf("%s\n", buf); + assert_se(calendar_spec_from_string(buf, &c) >= 0); + assert_se(calendar_spec_to_string(c, &t) >= 0); + calendar_spec_free(c); + printf("%s\n", t); + + assert_se(parse_timestamp(t, &y) >= 0); + assert_se(y == x); +} + int main(int argc, char* argv[]) { CalendarSpec *c; - test_one("Sat,Thu,Mon-Wed,Sat-Sun", "Mon-Thu,Sat,Sun *-*-* 00:00:00"); + test_one("Sat,Thu,Mon-Wed,Sat-Sun", "Mon..Thu,Sat,Sun *-*-* 00:00:00"); + test_one("Sat,Thu,Mon..Wed,Sat..Sun", "Mon..Thu,Sat,Sun *-*-* 00:00:00"); test_one("Mon,Sun 12-*-* 2,1:23", "Mon,Sun 2012-*-* 01,02:23:00"); test_one("Wed *-1", "Wed *-*-01 00:00:00"); test_one("Wed-Wed,Wed *-1", "Wed *-*-01 00:00:00"); + test_one("Wed..Wed,Wed *-1", "Wed *-*-01 00:00:00"); test_one("Wed, 17:48", "Wed *-*-* 17:48:00"); - test_one("Wed-Sat,Tue 12-10-15 1:2:3", "Tue-Sat 2012-10-15 01:02:03"); + test_one("Wed-Sat,Tue 12-10-15 1:2:3", "Tue..Sat 2012-10-15 01:02:03"); + test_one("Wed..Sat,Tue 12-10-15 1:2:3", "Tue..Sat 2012-10-15 01:02:03"); test_one("*-*-7 0:0:0", "*-*-07 00:00:00"); test_one("10-15", "*-10-15 00:00:00"); test_one("monday *-12-* 17:00", "Mon *-12-* 17:00:00"); @@ -82,11 +144,39 @@ int main(int argc, char* argv[]) { test_one("semi-annually", "*-01,07-01 00:00:00"); test_one("annually", "*-01-01 00:00:00"); test_one("*:2/3", "*-*-* *:02/3:00"); + test_one("2015-10-25 01:00:00 uTc", "2015-10-25 01:00:00 UTC"); + test_one("2016-03-27 03:17:00.4200005", "2016-03-27 03:17:00.420001"); + test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000"); + test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000"); + test_one("9..11,13:00,30", "*-*-* 09,10,11,13:00,30:00"); + test_one("1..3-1..3 1..3:1..3", "*-01,02,03-01,02,03 01,02,03:01,02,03:00"); + test_one("00:00:1.125..2.125", "*-*-* 00:00:01.125000,02.125000"); + test_one("00:00:1.0..3.8", "*-*-* 00:00:01,02,03"); + + test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000); + test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000); + test_next("2016-03-27 03:17:00", "EET", 12345, -1); + test_next("2016-03-27 03:17:00 UTC", NULL, 12345, 1459048620000000); + test_next("2016-03-27 03:17:00 UTC", "", 12345, 1459048620000000); + test_next("2016-03-27 03:17:00 UTC", "CET", 12345, 1459048620000000); + test_next("2016-03-27 03:17:00 UTC", "EET", 12345, 1459048620000000); + test_next("2016-03-27 03:17:00.420000001 UTC", "EET", 12345, 1459048620420000); + test_next("2016-03-27 03:17:00.4200005 UTC", "EET", 12345, 1459048620420001); + test_next("2015-11-13 09:11:23.42", "EET", 12345, 1447398683420000); + test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683420000, 1447398685190000); + test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683419999, 1447398683420000); + test_next("Sun 16:00:00", "CET", 1456041600123456, 1456066800000000); assert_se(calendar_spec_from_string("test", &c) < 0); assert_se(calendar_spec_from_string("", &c) < 0); assert_se(calendar_spec_from_string("7", &c) < 0); assert_se(calendar_spec_from_string("121212:1:2", &c) < 0); + assert_se(calendar_spec_from_string("2000-03-05.23 00:00:00", &c) < 0); + assert_se(calendar_spec_from_string("2000-03-05 00:00.1:00", &c) < 0); + assert_se(calendar_spec_from_string("00:00:00/0.00000001", &c) < 0); + assert_se(calendar_spec_from_string("00:00:00.0..00.9", &c) < 0); + + test_timestamp(); return 0; } diff --git a/src/test/test-cap-list.c b/src/test/test-cap-list.c index 43a2d35b80..4132ec56fd 100644 --- a/src/test/test-cap-list.c +++ b/src/test/test-cap-list.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,12 +17,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "fileio.h" -#include "cap-list.h" -#include "capability.h" #include <sys/prctl.h> +#include "alloc-util.h" +#include "cap-list.h" +#include "capability-util.h" +#include "fileio.h" +#include "parse-util.h" +#include "util.h" + /* verify the capability parser */ static void test_cap_list(void) { int i; diff --git a/src/test/test-capability.c b/src/test/test-capability.c index f47452ce72..629bb63c81 100644 --- a/src/test/test-capability.c +++ b/src/test/test-capability.c @@ -17,20 +17,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/wait.h> -#include <sys/capability.h> -#include <sys/socket.h> #include <netinet/in.h> #include <pwd.h> +#include <sys/capability.h> +#include <sys/prctl.h> +#include <sys/socket.h> +#include <sys/wait.h> #include <unistd.h> -#include "capability.h" -#include "util.h" +#include "capability-util.h" +#include "fd-util.h" #include "macro.h" +#include "util.h" static uid_t test_uid = -1; static gid_t test_gid = -1; -// We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage + +/* We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage */ static uint64_t test_flags = 1ULL << CAP_DAC_OVERRIDE; static void fork_test(void (*test_func)(void)) { @@ -64,8 +67,9 @@ static void show_capabilities(void) { cap_free(text); } -static int setup_tests(void) { +static int setup_tests(bool *run_ambient) { struct passwd *nobody; + int r; nobody = getpwnam("nobody"); if (!nobody) { @@ -75,6 +79,18 @@ static int setup_tests(void) { test_uid = nobody->pw_uid; test_gid = nobody->pw_gid; + *run_ambient = false; + + r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0); + + /* There's support for PR_CAP_AMBIENT if the prctl() call + * succeeded or error code was something else than EINVAL. The + * EINVAL check should be good enough to rule out false + * positives. */ + + if (r >= 0 || errno != EINVAL) + *run_ambient = true; + return 0; } @@ -138,8 +154,53 @@ static void test_have_effective_cap(void) { assert_se(!have_effective_cap(CAP_CHOWN)); } +static void test_update_inherited_set(void) { + cap_t caps; + uint64_t set = 0; + cap_flag_value_t fv; + + caps = cap_get_proc(); + assert_se(caps); + assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); + assert(fv == CAP_CLEAR); + + set = (UINT64_C(1) << CAP_CHOWN); + + assert_se(!capability_update_inherited_set(caps, set)); + assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); + assert(fv == CAP_SET); + + cap_free(caps); +} + +static void test_set_ambient_caps(void) { + cap_t caps; + uint64_t set = 0; + cap_flag_value_t fv; + + caps = cap_get_proc(); + assert_se(caps); + assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); + assert(fv == CAP_CLEAR); + cap_free(caps); + + assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 0); + + set = (UINT64_C(1) << CAP_CHOWN); + + assert_se(!capability_ambient_set_apply(set, true)); + + caps = cap_get_proc(); + assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); + assert(fv == CAP_SET); + cap_free(caps); + + assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 1); +} + int main(int argc, char *argv[]) { int r; + bool run_ambient; log_parse_environment(); log_open(); @@ -147,14 +208,19 @@ int main(int argc, char *argv[]) { if (getuid() != 0) return EXIT_TEST_SKIP; - r = setup_tests(); + r = setup_tests(&run_ambient); if (r < 0) return -r; show_capabilities(); test_drop_privileges(); + test_update_inherited_set(); + fork_test(test_have_effective_cap); + if (run_ambient) + fork_test(test_set_ambient_caps); + return 0; } diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c index 72f874d8a9..a027eb0fd2 100644 --- a/src/test/test-cgroup-mask.c +++ b/src/test/test-cgroup-mask.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,10 +19,12 @@ #include <stdio.h> -#include "manager.h" -#include "unit.h" #include "macro.h" +#include "manager.h" +#include "rm-rf.h" #include "test-helper.h" +#include "tests.h" +#include "unit.h" static int test_cgroup_mask(void) { Manager *m = NULL; @@ -35,12 +35,24 @@ static int test_cgroup_mask(void) { /* Prepare the manager. */ assert_se(set_unit_path(TEST_DIR) >= 0); - r = manager_new(MANAGER_USER, true, &m); + r = manager_new(UNIT_FILE_USER, true, &m); if (r == -EPERM || r == -EACCES) { puts("manager_new: Permission denied. Skipping test."); return EXIT_TEST_SKIP; } assert_se(r >= 0); + + /* Turn off all kinds of default accouning, so that we can + * verify the masks resulting of our configuration and nothing + * else. */ + m->default_cpu_accounting = + m->default_memory_accounting = + m->default_blockio_accounting = + m->default_io_accounting = + m->default_tasks_accounting = false; + m->default_tasks_max = (uint64_t) -1; + + assert_se(r >= 0); assert_se(manager_startup(m, serial, fdset) >= 0); /* Load units and verify hierarchy. */ @@ -61,36 +73,36 @@ static int test_cgroup_mask(void) { root = UNIT_DEREF(parent->slice); /* Verify per-unit cgroups settings. */ - assert_se(unit_get_cgroup_mask(son) == (CGROUP_CPU | CGROUP_CPUACCT)); - assert_se(unit_get_cgroup_mask(daughter) == 0); - assert_se(unit_get_cgroup_mask(grandchild) == 0); - assert_se(unit_get_cgroup_mask(parent_deep) == CGROUP_MEMORY); - assert_se(unit_get_cgroup_mask(parent) == CGROUP_BLKIO); - assert_se(unit_get_cgroup_mask(root) == 0); + assert_se(unit_get_own_mask(son) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT)); + assert_se(unit_get_own_mask(daughter) == 0); + assert_se(unit_get_own_mask(grandchild) == 0); + assert_se(unit_get_own_mask(parent_deep) == CGROUP_MASK_MEMORY); + assert_se(unit_get_own_mask(parent) == (CGROUP_MASK_IO | CGROUP_MASK_BLKIO)); + assert_se(unit_get_own_mask(root) == 0); /* Verify aggregation of member masks */ assert_se(unit_get_members_mask(son) == 0); assert_se(unit_get_members_mask(daughter) == 0); assert_se(unit_get_members_mask(grandchild) == 0); assert_se(unit_get_members_mask(parent_deep) == 0); - assert_se(unit_get_members_mask(parent) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY)); - assert_se(unit_get_members_mask(root) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY)); + assert_se(unit_get_members_mask(parent) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY)); + assert_se(unit_get_members_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); /* Verify aggregation of sibling masks. */ - assert_se(unit_get_siblings_mask(son) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY)); - assert_se(unit_get_siblings_mask(daughter) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY)); + assert_se(unit_get_siblings_mask(son) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY)); + assert_se(unit_get_siblings_mask(daughter) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY)); assert_se(unit_get_siblings_mask(grandchild) == 0); - assert_se(unit_get_siblings_mask(parent_deep) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY)); - assert_se(unit_get_siblings_mask(parent) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY)); - assert_se(unit_get_siblings_mask(root) == (CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY)); + assert_se(unit_get_siblings_mask(parent_deep) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY)); + assert_se(unit_get_siblings_mask(parent) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); + assert_se(unit_get_siblings_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY)); /* Verify aggregation of target masks. */ - assert_se(unit_get_target_mask(son) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); - assert_se(unit_get_target_mask(daughter) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); + assert_se(unit_get_target_mask(son) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported)); + assert_se(unit_get_target_mask(daughter) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported)); assert_se(unit_get_target_mask(grandchild) == 0); - assert_se(unit_get_target_mask(parent_deep) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_MEMORY) & m->cgroup_supported)); - assert_se(unit_get_target_mask(parent) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY) & m->cgroup_supported)); - assert_se(unit_get_target_mask(root) == ((CGROUP_CPU | CGROUP_CPUACCT | CGROUP_BLKIO | CGROUP_MEMORY) & m->cgroup_supported)); + assert_se(unit_get_target_mask(parent_deep) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported)); + assert_se(unit_get_target_mask(parent) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported)); + assert_se(unit_get_target_mask(root) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported)); manager_free(m); @@ -98,7 +110,11 @@ static int test_cgroup_mask(void) { } int main(int argc, char* argv[]) { + _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; int rc = 0; + + assert_se(runtime_dir = setup_fake_runtime_dir()); TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask()); + return rc; } diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c index ecc9d70bf4..c24c784e9b 100644 --- a/src/test/test-cgroup-util.c +++ b/src/test/test-cgroup-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,12 +17,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - -#include "util.h" +#include "alloc-util.h" #include "cgroup-util.h" -#include "test-helper.h" +#include "dirent-util.h" +#include "fd-util.h" #include "formats-util.h" +#include "parse-util.h" #include "process-util.h" +#include "stat-util.h" +#include "string-util.h" +#include "test-helper.h" +#include "user-util.h" +#include "util.h" static void check_p_d_u(const char *path, int code, const char *result) { _cleanup_free_ char *unit = NULL; @@ -295,6 +299,39 @@ static void test_shift_path(void) { test_shift_path_one("/foobar/waldo", "/fuckfuck", "/foobar/waldo"); } +static void test_mask_supported(void) { + + CGroupMask m; + CGroupController c; + + assert_se(cg_mask_supported(&m) >= 0); + + for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) + printf("'%s' is supported: %s\n", cgroup_controller_to_string(c), yes_no(m & CGROUP_CONTROLLER_TO_MASK(c))); +} + +static void test_is_cgroup_fs(void) { + struct statfs sfs; + assert_se(statfs("/sys/fs/cgroup", &sfs) == 0); + if (is_temporary_fs(&sfs)) + assert_se(statfs("/sys/fs/cgroup/systemd", &sfs) == 0); + assert_se(is_cgroup_fs(&sfs)); +} + +static void test_fd_is_cgroup_fs(void) { + int fd; + + fd = open("/sys/fs/cgroup", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); + assert_se(fd >= 0); + if (fd_is_temporary_fs(fd)) { + fd = safe_close(fd); + fd = open("/sys/fs/cgroup/systemd", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); + assert_se(fd >= 0); + } + assert_se(fd_is_cgroup_fs(fd)); + fd = safe_close(fd); +} + int main(void) { test_path_decode_unit(); test_path_get_unit(); @@ -309,6 +346,9 @@ int main(void) { test_controller_is_valid(); test_slice_to_path(); test_shift_path(); + TEST_REQ_RUNNING_SYSTEMD(test_mask_supported()); + TEST_REQ_RUNNING_SYSTEMD(test_is_cgroup_fs()); + TEST_REQ_RUNNING_SYSTEMD(test_fd_is_cgroup_fs()); return 0; } diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c index 4be69a408d..5336c19652 100644 --- a/src/test/test-cgroup.c +++ b/src/test/test-cgroup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,11 +17,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <string.h> +#include <unistd.h> #include "cgroup-util.h" #include "path-util.h" +#include "string-util.h" #include "util.h" int main(int argc, char*argv[]) { @@ -56,26 +55,26 @@ int main(int argc, char*argv[]) { assert_se(path_equal(path, "/sys/fs/cgroup/systemd/test-b/test-d")); free(path); - assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) > 0); - assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) > 0); - assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) > 0); - assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) == 0); + assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-a") > 0); + assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, "/test-b") > 0); + assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a") > 0); + assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b") == 0); - assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, false, false, false, NULL) == 0); - assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, false, false, false, NULL) > 0); + assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, 0, NULL, NULL, NULL) == 0); + assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, 0, NULL, NULL, NULL) > 0); - assert_se(cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", SYSTEMD_CGROUP_CONTROLLER, "/test-a", false, false) > 0); + assert_se(cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0) > 0); - assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", false) == 0); - assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", false) > 0); + assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a") == 0); + assert_se(cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b") > 0); - assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, false, false, false, NULL) > 0); - assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, false, false, false, NULL) == 0); + assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-a", 0, 0, NULL, NULL, NULL) > 0); + assert_se(cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, "/test-b", 0, 0, NULL, NULL, NULL) == 0); cg_trim(SYSTEMD_CGROUP_CONTROLLER, "/", false); - assert_se(cg_delete(SYSTEMD_CGROUP_CONTROLLER, "/test-b") < 0); - assert_se(cg_delete(SYSTEMD_CGROUP_CONTROLLER, "/test-a") >= 0); + assert_se(cg_rmdir(SYSTEMD_CGROUP_CONTROLLER, "/test-b") < 0); + assert_se(cg_rmdir(SYSTEMD_CGROUP_CONTROLLER, "/test-a") >= 0); assert_se(cg_split_spec("foobar:/", &c, &p) == 0); assert_se(streq(c, "foobar")); diff --git a/src/test/test-clock.c b/src/test/test-clock.c new file mode 100644 index 0000000000..7d97328416 --- /dev/null +++ b/src/test/test-clock.c @@ -0,0 +1,96 @@ +/*** + This file is part of systemd. + + Copyright (C) 2016 Canonical Ltd. + + 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 <unistd.h> +#include <fcntl.h> + +#include "clock-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "log.h" +#include "macro.h" + +static void test_clock_is_localtime(void) { + char adjtime[] = "/tmp/test-adjtime.XXXXXX"; + int fd = -1; + _cleanup_fclose_ FILE* f = NULL; + + static const struct scenario { + const char* contents; + int expected_result; + } scenarios[] = { + /* adjtime configures UTC */ + {"0.0 0 0\n0\nUTC\n", 0}, + /* adjtime configures local time */ + {"0.0 0 0\n0\nLOCAL\n", 1}, + /* no final EOL */ + {"0.0 0 0\n0\nUTC", 0}, + {"0.0 0 0\n0\nLOCAL", 1}, + /* empty value -> defaults to UTC */ + {"0.0 0 0\n0\n", 0}, + /* unknown value -> defaults to UTC */ + {"0.0 0 0\n0\nFOO\n", 0}, + /* no third line */ + {"0.0 0 0", 0}, + {"0.0 0 0\n", 0}, + {"0.0 0 0\n0", 0}, + }; + + /* without an adjtime file we default to UTC */ + assert_se(clock_is_localtime("/nonexisting/adjtime") == 0); + + fd = mkostemp_safe(adjtime); + assert_se(fd >= 0); + log_info("adjtime test file: %s", adjtime); + f = fdopen(fd, "w"); + assert_se(f); + + for (size_t i = 0; i < ELEMENTSOF(scenarios); ++i) { + log_info("scenario #%zu:, expected result %i", i, scenarios[i].expected_result); + log_info("%s", scenarios[i].contents); + rewind(f); + ftruncate(fd, 0); + assert_se(write_string_stream(f, scenarios[i].contents, false) == 0); + assert_se(clock_is_localtime(adjtime) == scenarios[i].expected_result); + } + + unlink(adjtime); +} + +/* Test with the real /etc/adjtime */ +static void test_clock_is_localtime_system(void) { + int r; + r = clock_is_localtime(NULL); + + if (access("/etc/adjtime", F_OK) == 0) { + log_info("/etc/adjtime exists, clock_is_localtime() == %i", r); + /* if /etc/adjtime exists we expect some answer, no error or + * crash */ + assert_se(r == 0 || r == 1); + } else + /* default is UTC if there is no /etc/adjtime */ + assert_se(r == 0); +} + +int main(int argc, char *argv[]) { + test_clock_is_localtime(); + test_clock_is_localtime_system(); + + return 0; +} diff --git a/src/test/test-condition.c b/src/test/test-condition.c index b788c9532d..6f7d71ef9a 100644 --- a/src/test/test-condition.c +++ b/src/test/test-condition.c @@ -17,83 +17,102 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "sd-id128.h" + +#include "alloc-util.h" +#include "apparmor-util.h" +#include "architecture.h" +#include "audit-util.h" #include "condition.h" -#include "macro.h" -#include "util.h" +#include "hostname-util.h" +#include "id128-util.h" +#include "ima-util.h" #include "log.h" -#include "architecture.h" -#include "sd-id128.h" +#include "macro.h" #include "selinux-util.h" -#include "audit.h" -#include "ima-util.h" -#include "apparmor-util.h" #include "smack-util.h" -#include "hostname-util.h" +#include "util.h" static void test_condition_test_path(void) { Condition *condition; condition = condition_new(CONDITION_PATH_EXISTS, "/bin/sh", false, false); + assert_se(condition); assert_se(condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_PATH_EXISTS, "/bin/s?", false, false); + assert_se(condition); assert_se(!condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_PATH_EXISTS_GLOB, "/bin/s?", false, false); + assert_se(condition); assert_se(condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_PATH_EXISTS_GLOB, "/bin/s?", false, true); + assert_se(condition); assert_se(!condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_PATH_EXISTS, "/thiscertainlywontexist", false, false); + assert_se(condition); assert_se(!condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_PATH_EXISTS, "/thiscertainlywontexist", false, true); + assert_se(condition); assert_se(condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_PATH_IS_DIRECTORY, "/bin", false, false); + assert_se(condition); assert_se(condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_DIRECTORY_NOT_EMPTY, "/bin", false, false); + assert_se(condition); assert_se(condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_FILE_NOT_EMPTY, "/bin/sh", false, false); + assert_se(condition); assert_se(condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_FILE_IS_EXECUTABLE, "/bin/sh", false, false); + assert_se(condition); assert_se(condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_FILE_IS_EXECUTABLE, "/etc/passwd", false, false); + assert_se(condition); assert_se(!condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/proc", false, false); + assert_se(condition); assert_se(condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/", false, false); + assert_se(condition); assert_se(condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/bin", false, false); + assert_se(condition); assert_se(!condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_PATH_IS_READ_WRITE, "/tmp", false, false); + assert_se(condition); assert_se(condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_PATH_IS_SYMBOLIC_LINK, "/dev/stdout", false, false); + assert_se(condition); assert_se(condition_test(condition)); condition_free(condition); } @@ -102,47 +121,59 @@ static void test_condition_test_ac_power(void) { Condition *condition; condition = condition_new(CONDITION_AC_POWER, "true", false, false); + assert_se(condition); assert_se(condition_test(condition) == on_ac_power()); condition_free(condition); condition = condition_new(CONDITION_AC_POWER, "false", false, false); + assert_se(condition); assert_se(condition_test(condition) != on_ac_power()); condition_free(condition); condition = condition_new(CONDITION_AC_POWER, "false", false, true); + assert_se(condition); assert_se(condition_test(condition) == on_ac_power()); condition_free(condition); } static void test_condition_test_host(void) { + _cleanup_free_ char *hostname = NULL; + char sid[SD_ID128_STRING_MAX]; Condition *condition; sd_id128_t id; int r; - char sid[SD_ID128_STRING_MAX]; - _cleanup_free_ char *hostname = NULL; r = sd_id128_get_machine(&id); assert_se(r >= 0); assert_se(sd_id128_to_string(id, sid)); condition = condition_new(CONDITION_HOST, sid, false, false); + assert_se(condition); assert_se(condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_HOST, "garbage value jjjjjjjjjjjjjj", false, false); + assert_se(condition); assert_se(!condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_HOST, sid, false, true); + assert_se(condition); assert_se(!condition_test(condition)); condition_free(condition); hostname = gethostname_malloc(); assert_se(hostname); - condition = condition_new(CONDITION_HOST, hostname, false, false); - assert_se(condition_test(condition)); - condition_free(condition); + /* if hostname looks like an id128 then skip testing it */ + if (id128_is_valid(hostname)) + log_notice("hostname is an id128, skipping test"); + else { + condition = condition_new(CONDITION_HOST, hostname, false, false); + assert_se(condition); + assert_se(condition_test(condition)); + condition_free(condition); + } } static void test_condition_test_architecture(void) { @@ -157,15 +188,18 @@ static void test_condition_test_architecture(void) { assert_se(sa); condition = condition_new(CONDITION_ARCHITECTURE, sa, false, false); - assert_se(condition_test(condition)); + assert_se(condition); + assert_se(condition_test(condition) > 0); condition_free(condition); condition = condition_new(CONDITION_ARCHITECTURE, "garbage value", false, false); - assert_se(condition_test(condition) < 0); + assert_se(condition); + assert_se(condition_test(condition) == 0); condition_free(condition); condition = condition_new(CONDITION_ARCHITECTURE, sa, false, true); - assert_se(!condition_test(condition)); + assert_se(condition); + assert_se(condition_test(condition) == 0); condition_free(condition); } @@ -173,10 +207,12 @@ static void test_condition_test_kernel_command_line(void) { Condition *condition; condition = condition_new(CONDITION_KERNEL_COMMAND_LINE, "thisreallyshouldntbeonthekernelcommandline", false, false); + assert_se(condition); assert_se(!condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_KERNEL_COMMAND_LINE, "andthis=neither", false, false); + assert_se(condition); assert_se(!condition_test(condition)); condition_free(condition); } @@ -185,10 +221,12 @@ static void test_condition_test_null(void) { Condition *condition; condition = condition_new(CONDITION_NULL, NULL, false, false); + assert_se(condition); assert_se(condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_NULL, NULL, false, true); + assert_se(condition); assert_se(!condition_test(condition)); condition_free(condition); } @@ -197,31 +235,36 @@ static void test_condition_test_security(void) { Condition *condition; condition = condition_new(CONDITION_SECURITY, "garbage oifdsjfoidsjoj", false, false); + assert_se(condition); assert_se(!condition_test(condition)); condition_free(condition); condition = condition_new(CONDITION_SECURITY, "selinux", false, true); - assert_se(condition_test(condition) != mac_selinux_use()); + assert_se(condition); + assert_se(condition_test(condition) != mac_selinux_have()); condition_free(condition); condition = condition_new(CONDITION_SECURITY, "ima", false, false); + assert_se(condition); assert_se(condition_test(condition) == use_ima()); condition_free(condition); condition = condition_new(CONDITION_SECURITY, "apparmor", false, false); + assert_se(condition); assert_se(condition_test(condition) == mac_apparmor_use()); condition_free(condition); condition = condition_new(CONDITION_SECURITY, "smack", false, false); + assert_se(condition); assert_se(condition_test(condition) == mac_smack_use()); condition_free(condition); condition = condition_new(CONDITION_SECURITY, "audit", false, false); + assert_se(condition); assert_se(condition_test(condition) == use_audit()); condition_free(condition); } - int main(int argc, char *argv[]) { log_parse_environment(); log_open(); diff --git a/src/test/test-conf-files.c b/src/test/test-conf-files.c index 01ece022c1..03b3a9fa5c 100644 --- a/src/test/test-conf-files.c +++ b/src/test/test-conf-files.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,14 +17,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <stdarg.h> +#include <stdio.h> +#include "alloc-util.h" #include "conf-files.h" +#include "fs-util.h" #include "macro.h" +#include "parse-util.h" +#include "rm-rf.h" +#include "string-util.h" #include "strv.h" +#include "user-util.h" #include "util.h" -#include "rm-rf.h" static void setup_test_dir(char *tmp_dir, const char *files, ...) { va_list ap; @@ -36,7 +39,7 @@ static void setup_test_dir(char *tmp_dir, const char *files, ...) { va_start(ap, files); while (files != NULL) { _cleanup_free_ char *path = strappend(tmp_dir, files); - assert_se(touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0) == 0); + assert_se(touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID) == 0); files = va_arg(ap, const char *); } va_end(ap); diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index 463906d304..be5d2611f8 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -18,10 +18,11 @@ ***/ #include "conf-parser.h" +#include "log.h" #include "macro.h" -#include "util.h" +#include "string-util.h" #include "strv.h" -#include "log.h" +#include "util.h" static void test_config_parse_path_one(const char *rvalue, const char *expected) { char *path = NULL; @@ -214,6 +215,14 @@ static void test_config_parse_nsec(void) { test_config_parse_nsec_one("garbage", 0); } +static void test_config_parse_iec_uint64(void) { + uint64_t offset = 0; + assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0); + assert_se(offset == 4 * 1024 * 1024); + + assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0); +} + int main(int argc, char **argv) { log_parse_environment(); log_open(); @@ -229,6 +238,7 @@ int main(int argc, char **argv) { test_config_parse_mode(); test_config_parse_sec(); test_config_parse_nsec(); + test_config_parse_iec_uint64(); return 0; } diff --git a/src/test/test-copy.c b/src/test/test-copy.c index b73c958ec5..ed1ea51dbd 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -19,14 +19,19 @@ #include <unistd.h> +#include "alloc-util.h" #include "copy.h" -#include "path-util.h" +#include "fd-util.h" #include "fileio.h" +#include "fs-util.h" +#include "log.h" +#include "macro.h" #include "mkdir.h" +#include "path-util.h" +#include "rm-rf.h" +#include "string-util.h" #include "strv.h" -#include "macro.h" #include "util.h" -#include "rm-rf.h" static void test_copy_file(void) { _cleanup_free_ char *buf = NULL; @@ -35,11 +40,13 @@ static void test_copy_file(void) { size_t sz = 0; int fd; - fd = mkostemp_safe(fn, O_RDWR|O_CLOEXEC); + log_info("%s", __func__); + + fd = mkostemp_safe(fn); assert_se(fd >= 0); close(fd); - fd = mkostemp_safe(fn_copy, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(fn_copy); assert_se(fd >= 0); close(fd); @@ -62,9 +69,11 @@ static void test_copy_file_fd(void) { char text[] = "boohoo\nfoo\n\tbar\n"; char buf[64] = {0}; - in_fd = mkostemp_safe(in_fn, O_RDWR); + log_info("%s", __func__); + + in_fd = mkostemp_safe(in_fn); assert_se(in_fd >= 0); - out_fd = mkostemp_safe(out_fn, O_RDWR); + out_fd = mkostemp_safe(out_fn); assert_se(out_fd >= 0); assert_se(write_string_file(in_fn, text, WRITE_STRING_FILE_CREATE) == 0); @@ -86,31 +95,43 @@ static void test_copy_tree(void) { char **links = STRV_MAKE("link", "file", "link2", "dir1/file"); char **p, **link; + const char *unixsockp; + struct stat st; + + log_info("%s", __func__); (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL); (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL); STRV_FOREACH(p, files) { - char *f = strjoina(original_dir, *p); + _cleanup_free_ char *f; + + assert_se(f = strappend(original_dir, *p)); assert_se(mkdir_parents(f, 0755) >= 0); assert_se(write_string_file(f, "file", WRITE_STRING_FILE_CREATE) == 0); } STRV_FOREACH_PAIR(link, p, links) { - char *f = strjoina(original_dir, *p); - char *l = strjoina(original_dir, *link); + _cleanup_free_ char *f, *l; + + assert_se(f = strappend(original_dir, *p)); + assert_se(l = strappend(original_dir, *link)); assert_se(mkdir_parents(l, 0755) >= 0); assert_se(symlink(f, l) == 0); } + unixsockp = strjoina(original_dir, "unixsock"); + assert_se(mknod(unixsockp, S_IFSOCK|0644, 0) >= 0); + assert_se(copy_tree(original_dir, copy_dir, true) == 0); STRV_FOREACH(p, files) { - _cleanup_free_ char *buf = NULL; + _cleanup_free_ char *buf = NULL, *f; size_t sz = 0; - char *f = strjoina(copy_dir, *p); + + assert_se(f = strappend(copy_dir, *p)); assert_se(access(f, F_OK) == 0); assert_se(read_full_file(f, &buf, &sz) == 0); @@ -118,14 +139,19 @@ static void test_copy_tree(void) { } STRV_FOREACH_PAIR(link, p, links) { - _cleanup_free_ char *target = NULL; - char *f = strjoina(original_dir, *p); - char *l = strjoina(copy_dir, *link); + _cleanup_free_ char *target = NULL, *f, *l; + + assert_se(f = strjoin(original_dir, *p, NULL)); + assert_se(l = strjoin(copy_dir, *link, NULL)); assert_se(readlink_and_canonicalize(l, &target) == 0); assert_se(path_equal(f, target)); } + unixsockp = strjoina(copy_dir, "unixsock"); + assert_se(stat(unixsockp, &st) >= 0); + assert_se(S_ISSOCK(st.st_mode)); + assert_se(copy_tree(original_dir, copy_dir, false) < 0); assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, false) < 0); @@ -146,7 +172,7 @@ static void test_copy_bytes(void) { assert_se(pipe2(pipefd, O_CLOEXEC) == 0); - r = copy_bytes(infd, pipefd[1], (off_t) -1, false); + r = copy_bytes(infd, pipefd[1], (uint64_t) -1, false); assert_se(r == 0); r = read(pipefd[0], buf, sizeof(buf)); @@ -169,11 +195,65 @@ static void test_copy_bytes(void) { assert_se(r == -EBADF); } +static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint64_t max_bytes) { + char fn2[] = "/tmp/test-copy-file-XXXXXX"; + char fn3[] = "/tmp/test-copy-file-XXXXXX"; + _cleanup_close_ int fd = -1, fd2 = -1, fd3 = -1; + int r; + struct stat buf, buf2, buf3; + + log_info("%s try_reflink=%s max_bytes=%" PRIu64, __func__, yes_no(try_reflink), max_bytes); + + fd = open(src, O_RDONLY | O_CLOEXEC | O_NOCTTY); + assert_se(fd >= 0); + + fd2 = mkostemp_safe(fn2); + assert_se(fd2 >= 0); + + fd3 = mkostemp_safe(fn3); + assert_se(fd3 >= 0); + + r = copy_bytes(fd, fd2, max_bytes, try_reflink); + if (max_bytes == (uint64_t) -1) + assert_se(r == 0); + else + assert_se(IN_SET(r, 0, 1)); + + assert_se(lseek(fd2, 0, SEEK_SET) == 0); + + r = copy_bytes(fd2, fd3, max_bytes, try_reflink); + if (max_bytes == (uint64_t) -1) + assert_se(r == 0); + else + /* We cannot distinguish between the input being exactly max_bytes + * or longer than max_bytes (without trying to read one more byte, + * or calling stat, or FION_READ, etc, and we don't want to do any + * of that). So we expect "truncation" since we know that file we + * are copying is exactly max_bytes bytes. */ + assert_se(r == 1); + + assert_se(fstat(fd, &buf) == 0); + assert_se(fstat(fd2, &buf2) == 0); + assert_se(fstat(fd3, &buf3) == 0); + + assert_se((uint64_t) buf2.st_size == MIN((uint64_t) buf.st_size, max_bytes)); + assert_se(buf3.st_size == buf2.st_size); + + unlink(fn2); + unlink(fn3); +} + int main(int argc, char *argv[]) { test_copy_file(); test_copy_file_fd(); test_copy_tree(); test_copy_bytes(); + test_copy_bytes_regular_file(argv[0], false, (uint64_t) -1); + test_copy_bytes_regular_file(argv[0], true, (uint64_t) -1); + test_copy_bytes_regular_file(argv[0], false, 1000); /* smaller than copy buffer size */ + test_copy_bytes_regular_file(argv[0], true, 1000); + test_copy_bytes_regular_file(argv[0], false, 32000); /* larger than copy buffer size */ + test_copy_bytes_regular_file(argv[0], true, 32000); return 0; } diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c new file mode 100644 index 0000000000..8818d1ffb7 --- /dev/null +++ b/src/test/test-cpu-set-util.c @@ -0,0 +1,143 @@ +/*** + This file is part of systemd. + + Copyright 2010 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 "alloc-util.h" +#include "cpu-set-util.h" +#include "macro.h" + +static void test_parse_cpu_set(void) { + cpu_set_t *c = NULL; + int ncpus; + int cpu; + + /* Simple range (from CPUAffinity example) */ + ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2); + c = mfree(c); + + /* A more interesting range */ + ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Quoted strings */ + ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Use commas as separators */ + ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Commas with spaces (and trailing comma, space) */ + ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 8; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Ranges */ + ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Ranges with trailing comma, space */ + ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Negative range (returns empty cpu_set) */ + ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0); + c = mfree(c); + + /* Overlapping ranges */ + ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12); + for (cpu = 0; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Mix ranges and individual CPUs */ + ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10); + assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 4; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Garbage */ + ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); + + /* Range with garbage */ + ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); + + /* Empty string */ + c = NULL; + ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus == 0); /* empty string returns 0 */ + assert_se(!c); + + /* Runnaway quoted string */ + ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); +} + +int main(int argc, char *argv[]) { + test_parse_cpu_set(); + + return 0; +} diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c index 7e0ac754d1..a7cb426282 100644 --- a/src/test/test-daemon.c +++ b/src/test/test-daemon.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,33 +19,46 @@ #include <unistd.h> -#include "systemd/sd-daemon.h" +#include "sd-daemon.h" + +#include "strv.h" int main(int argc, char*argv[]) { + _cleanup_strv_free_ char **l = NULL; + int n, i; + + n = sd_listen_fds_with_names(false, &l); + if (n < 0) { + log_error_errno(n, "Failed to get listening fds: %m"); + return EXIT_FAILURE; + } + + for (i = 0; i < n; i++) + log_info("fd=%i name=%s\n", SD_LISTEN_FDS_START + i, l[i]); sd_notify(0, "STATUS=Starting up"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Running\n" "READY=1"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Reloading\n" "RELOADING=1"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Running\n" "READY=1"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Quitting\n" "STOPPING=1"); - sleep(5); + sleep(1); - return 0; + return EXIT_SUCCESS; } diff --git a/src/test/test-date.c b/src/test/test-date.c index 00b569080c..7f497bb7d5 100644 --- a/src/test/test-date.c +++ b/src/test/test-date.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,18 +19,22 @@ #include <string.h> +#include "alloc-util.h" +#include "string-util.h" #include "util.h" -static void test_one(const char *p) { +static void test_should_pass(const char *p) { usec_t t, q; - char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX]; + char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX], *sp; assert_se(parse_timestamp(p, &t) >= 0); - format_timestamp(buf, sizeof(buf), t); + format_timestamp_us(buf, sizeof(buf), t); log_info("%s", buf); /* Chop off timezone */ - *strrchr(buf, ' ') = 0; + sp = strrchr(buf, ' '); + assert_se(sp); + *sp = 0; assert_se(parse_timestamp(buf, &q) >= 0); assert_se(q == t); @@ -42,23 +44,57 @@ static void test_one(const char *p) { assert_se(parse_timestamp(buf, &q) >= 0); } +static void test_should_parse(const char *p) { + usec_t t; + + assert_se(parse_timestamp(p, &t) >= 0); +} + +static void test_should_fail(const char *p) { + usec_t t; + + assert_se(parse_timestamp(p, &t) < 0); +} + +static void test_one(const char *p) { + _cleanup_free_ char *with_utc; + + log_info("Test: %s", p); + with_utc = strjoin(p, " UTC", NULL); + test_should_pass(p); + test_should_pass(with_utc); +} + +static void test_one_noutc(const char *p) { + _cleanup_free_ char *with_utc; + + log_info("Test: %s", p); + with_utc = strjoin(p, " UTC", NULL); + test_should_pass(p); + test_should_fail(with_utc); +} + int main(int argc, char *argv[]) { test_one("17:41"); test_one("18:42:44"); + test_one("18:42:44.0"); + test_one("18:42:44.999999999999"); test_one("12-10-02 12:13:14"); test_one("12-10-2 12:13:14"); test_one("12-10-03 12:13"); test_one("2012-12-30 18:42"); test_one("2012-10-02"); test_one("Tue 2012-10-02"); - test_one("now"); + test_one_noutc("now"); test_one("yesterday"); test_one("today"); test_one("tomorrow"); - test_one("+2d"); - test_one("+2y 4d"); - test_one("5months ago"); - test_one("@1395716396"); + test_one_noutc("+2d"); + test_one_noutc("+2y 4d"); + test_one_noutc("5months ago"); + test_one_noutc("@1395716396"); + test_should_parse("today UTC"); + test_should_fail("today UTC UTC"); return 0; } diff --git a/src/test/test-device-nodes.c b/src/test/test-device-nodes.c index 59ba4be087..af75b38948 100644 --- a/src/test/test-device-nodes.c +++ b/src/test/test-device-nodes.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,7 +19,9 @@ #include <sys/types.h> +#include "alloc-util.h" #include "device-nodes.h" +#include "string-util.h" #include "util.h" /* helpers for test_encode_devnode_name */ diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c index 527cdd3b54..e2f097c95e 100644 --- a/src/test/test-dns-domain.c +++ b/src/test/test-dns-domain.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,8 +17,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "macro.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "macro.h" +#include "string-util.h" static void test_dns_label_unescape_one(const char *what, const char *expect, size_t buffer_sz, int ret) { char buffer[buffer_sz]; @@ -37,7 +37,7 @@ static void test_dns_label_unescape_one(const char *what, const char *expect, si static void test_dns_label_unescape(void) { test_dns_label_unescape_one("hallo", "hallo", 6, 5); - test_dns_label_unescape_one("hallo", "hallo", 4, -ENOSPC); + test_dns_label_unescape_one("hallo", "hallo", 4, -ENOBUFS); test_dns_label_unescape_one("", "", 10, 0); test_dns_label_unescape_one("hallo\\.foobar", "hallo.foobar", 20, 12); test_dns_label_unescape_one("hallo.foobar", "hallo", 10, 5); @@ -48,13 +48,114 @@ static void test_dns_label_unescape(void) { test_dns_label_unescape_one("..", "", 20, -EINVAL); test_dns_label_unescape_one(".foobar", "", 20, -EINVAL); test_dns_label_unescape_one("foobar.", "foobar", 20, 6); + test_dns_label_unescape_one("foobar..", "foobar", 20, -EINVAL); +} + +static void test_dns_name_to_wire_format_one(const char *what, const char *expect, size_t buffer_sz, int ret) { + uint8_t buffer[buffer_sz]; + int r; + + r = dns_name_to_wire_format(what, buffer, buffer_sz, false); + assert_se(r == ret); + + if (r < 0) + return; + + assert_se(!memcmp(buffer, expect, r)); +} + +static void test_dns_name_to_wire_format(void) { + static const char out0[] = { 0 }; + static const char out1[] = { 3, 'f', 'o', 'o', 0 }; + static const char out2[] = { 5, 'h', 'a', 'l', 'l', 'o', 3, 'f', 'o', 'o', 3, 'b', 'a', 'r', 0 }; + static const char out3[] = { 4, ' ', 'f', 'o', 'o', 3, 'b', 'a', 'r', 0 }; + static const char out4[] = { 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 3, 'a', '1', '2', 0 }; + + test_dns_name_to_wire_format_one("", out0, sizeof(out0), sizeof(out0)); + + test_dns_name_to_wire_format_one("foo", out1, sizeof(out1), sizeof(out1)); + test_dns_name_to_wire_format_one("foo", out1, sizeof(out1) + 1, sizeof(out1)); + test_dns_name_to_wire_format_one("foo", out1, sizeof(out1) - 1, -ENOBUFS); + + test_dns_name_to_wire_format_one("hallo.foo.bar", out2, sizeof(out2), sizeof(out2)); + test_dns_name_to_wire_format_one("hallo.foo..bar", NULL, 32, -EINVAL); + + test_dns_name_to_wire_format_one("\\032foo.bar", out3, sizeof(out3), sizeof(out3)); + + test_dns_name_to_wire_format_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a123", NULL, 500, -EINVAL); + test_dns_name_to_wire_format_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12", out4, sizeof(out4), sizeof(out4)); +} + +static void test_dns_label_unescape_suffix_one(const char *what, const char *expect1, const char *expect2, size_t buffer_sz, int ret1, int ret2) { + char buffer[buffer_sz]; + const char *label; + int r; + + label = what + strlen(what); + + r = dns_label_unescape_suffix(what, &label, buffer, buffer_sz); + assert_se(r == ret1); + if (r >= 0) + assert_se(streq(buffer, expect1)); + + r = dns_label_unescape_suffix(what, &label, buffer, buffer_sz); + assert_se(r == ret2); + if (r >= 0) + assert_se(streq(buffer, expect2)); +} + +static void test_dns_label_unescape_suffix(void) { + test_dns_label_unescape_suffix_one("hallo", "hallo", "", 6, 5, 0); + test_dns_label_unescape_suffix_one("hallo", "hallo", "", 4, -ENOBUFS, -ENOBUFS); + test_dns_label_unescape_suffix_one("", "", "", 10, 0, 0); + test_dns_label_unescape_suffix_one("hallo\\.foobar", "hallo.foobar", "", 20, 12, 0); + test_dns_label_unescape_suffix_one("hallo.foobar", "foobar", "hallo", 10, 6, 5); + test_dns_label_unescape_suffix_one("hallo.foobar\n", "foobar", "foobar", 20, -EINVAL, -EINVAL); + test_dns_label_unescape_suffix_one("hallo\\", "hallo", "hallo", 20, -EINVAL, -EINVAL); + test_dns_label_unescape_suffix_one("hallo\\032 ", "hallo ", "", 20, 7, 0); + test_dns_label_unescape_suffix_one(".", "", "", 20, 0, 0); + test_dns_label_unescape_suffix_one("..", "", "", 20, 0, -EINVAL); + test_dns_label_unescape_suffix_one(".foobar", "foobar", "", 20, 6, -EINVAL); + test_dns_label_unescape_suffix_one("foobar.", "foobar", "", 20, 6, 0); + test_dns_label_unescape_suffix_one("foo\\\\bar", "foo\\bar", "", 20, 7, 0); + test_dns_label_unescape_suffix_one("foo.bar", "bar", "foo", 20, 3, 3); + test_dns_label_unescape_suffix_one("foo..bar", "bar", "", 20, 3, -EINVAL); + test_dns_label_unescape_suffix_one("foo...bar", "bar", "", 20, 3, -EINVAL); + test_dns_label_unescape_suffix_one("foo\\.bar", "foo.bar", "", 20, 7, 0); + test_dns_label_unescape_suffix_one("foo\\\\.bar", "bar", "foo\\", 20, 3, 4); + test_dns_label_unescape_suffix_one("foo\\\\\\.bar", "foo\\.bar", "", 20, 8, 0); } static void test_dns_label_escape_one(const char *what, size_t l, const char *expect, int ret) { _cleanup_free_ char *t = NULL; int r; - r = dns_label_escape(what, l, &t); + r = dns_label_escape_new(what, l, &t); assert_se(r == ret); if (r < 0) @@ -64,9 +165,9 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex } static void test_dns_label_escape(void) { - test_dns_label_escape_one("", 0, "", 0); + test_dns_label_escape_one("", 0, NULL, -EINVAL); test_dns_label_escape_one("hallo", 5, "hallo", 5); - test_dns_label_escape_one("hallo", 6, NULL, -EINVAL); + test_dns_label_escape_one("hallo", 6, "hallo\\000", 9); test_dns_label_escape_one("hallo hallo.foobar,waldi", 24, "hallo\\032hallo\\.foobar\\044waldi", 31); } @@ -84,15 +185,15 @@ static void test_dns_name_normalize_one(const char *what, const char *expect, in } static void test_dns_name_normalize(void) { - test_dns_name_normalize_one("", "", 0); + test_dns_name_normalize_one("", ".", 0); test_dns_name_normalize_one("f", "f", 0); test_dns_name_normalize_one("f.waldi", "f.waldi", 0); test_dns_name_normalize_one("f \\032.waldi", "f\\032\\032.waldi", 0); - test_dns_name_normalize_one("\\000", NULL, -EINVAL); + test_dns_name_normalize_one("\\000", "\\000", 0); test_dns_name_normalize_one("..", NULL, -EINVAL); test_dns_name_normalize_one(".foobar", NULL, -EINVAL); test_dns_name_normalize_one("foobar.", "foobar", 0); - test_dns_name_normalize_one(".", "", 0); + test_dns_name_normalize_one(".", ".", 0); } static void test_dns_name_equal_one(const char *a, const char *b, int ret) { @@ -114,12 +215,44 @@ static void test_dns_name_equal(void) { test_dns_name_equal_one("abc.def", "CBA.def", false); test_dns_name_equal_one("", "xxx", false); test_dns_name_equal_one("ab", "a", false); - test_dns_name_equal_one("\\000", "xxxx", -EINVAL); + test_dns_name_equal_one("\\000", "\\000", true); test_dns_name_equal_one(".", "", true); test_dns_name_equal_one(".", ".", true); test_dns_name_equal_one("..", "..", -EINVAL); } +static void test_dns_name_between_one(const char *a, const char *b, const char *c, int ret) { + int r; + + r = dns_name_between(a, b, c); + assert_se(r == ret); + + r = dns_name_between(c, b, a); + if (ret >= 0) + assert_se(r == 0); + else + assert_se(r == ret); +} + +static void test_dns_name_between(void) { + /* see https://tools.ietf.org/html/rfc4034#section-6.1 + Note that we use "\033.z.example" in stead of "\001.z.example" as we + consider the latter invalid */ + test_dns_name_between_one("example", "a.example", "yljkjljk.a.example", true); + test_dns_name_between_one("a.example", "yljkjljk.a.example", "Z.a.example", true); + test_dns_name_between_one("yljkjljk.a.example", "Z.a.example", "zABC.a.EXAMPLE", true); + test_dns_name_between_one("Z.a.example", "zABC.a.EXAMPLE", "z.example", true); + test_dns_name_between_one("zABC.a.EXAMPLE", "z.example", "\\033.z.example", true); + test_dns_name_between_one("z.example", "\\033.z.example", "*.z.example", true); + test_dns_name_between_one("\\033.z.example", "*.z.example", "\\200.z.example", true); + test_dns_name_between_one("*.z.example", "\\200.z.example", "example", true); + test_dns_name_between_one("\\200.z.example", "example", "a.example", true); + + test_dns_name_between_one("example", "a.example", "example", -EINVAL); + test_dns_name_between_one("example", "example", "yljkjljk.a.example", false); + test_dns_name_between_one("example", "yljkjljk.a.example", "yljkjljk.a.example", false); +} + static void test_dns_name_endswith_one(const char *a, const char *b, int ret) { assert_se(dns_name_endswith(a, b) == ret); } @@ -142,21 +275,40 @@ static void test_dns_name_endswith(void) { test_dns_name_endswith_one("x.y\001.z", "waldo", -EINVAL); } -static void test_dns_name_root(void) { - assert_se(dns_name_root("") == true); - assert_se(dns_name_root(".") == true); - assert_se(dns_name_root("xxx") == false); - assert_se(dns_name_root("xxx.") == false); - assert_se(dns_name_root("..") == -EINVAL); +static void test_dns_name_startswith_one(const char *a, const char *b, int ret) { + assert_se(dns_name_startswith(a, b) == ret); } -static void test_dns_name_single_label(void) { - assert_se(dns_name_single_label("") == false); - assert_se(dns_name_single_label(".") == false); - assert_se(dns_name_single_label("..") == -EINVAL); - assert_se(dns_name_single_label("x") == true); - assert_se(dns_name_single_label("x.") == true); - assert_se(dns_name_single_label("xx.yy") == false); +static void test_dns_name_startswith(void) { + test_dns_name_startswith_one("", "", true); + test_dns_name_startswith_one("", "xxx", false); + test_dns_name_startswith_one("xxx", "", true); + test_dns_name_startswith_one("x", "x", true); + test_dns_name_startswith_one("x", "y", false); + test_dns_name_startswith_one("x.y", "x.y", true); + test_dns_name_startswith_one("x.y", "y.x", false); + test_dns_name_startswith_one("x.y", "x", true); + test_dns_name_startswith_one("x.y", "X", true); + test_dns_name_startswith_one("x.y", "y", false); + test_dns_name_startswith_one("x.y", "", true); + test_dns_name_startswith_one("x.y", "X", true); +} + +static void test_dns_name_is_root(void) { + assert_se(dns_name_is_root("")); + assert_se(dns_name_is_root(".")); + assert_se(!dns_name_is_root("xxx")); + assert_se(!dns_name_is_root("xxx.")); + assert_se(!dns_name_is_root("..")); +} + +static void test_dns_name_is_single_label(void) { + assert_se(!dns_name_is_single_label("")); + assert_se(!dns_name_is_single_label(".")); + assert_se(!dns_name_is_single_label("..")); + assert_se(dns_name_is_single_label("x")); + assert_se(dns_name_is_single_label("x.")); + assert_se(!dns_name_is_single_label("xx.yy")); } static void test_dns_name_reverse_one(const char *address, const char *name) { @@ -175,18 +327,333 @@ static void test_dns_name_reverse_one(const char *address, const char *name) { static void test_dns_name_reverse(void) { test_dns_name_reverse_one("47.11.8.15", "15.8.11.47.in-addr.arpa"); test_dns_name_reverse_one("fe80::47", "7.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa"); + test_dns_name_reverse_one("127.0.0.1", "1.0.0.127.in-addr.arpa"); + test_dns_name_reverse_one("::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa"); +} + +static void test_dns_name_concat_one(const char *a, const char *b, int r, const char *result) { + _cleanup_free_ char *p = NULL; + + assert_se(dns_name_concat(a, b, &p) == r); + assert_se(streq_ptr(p, result)); +} + +static void test_dns_name_concat(void) { + test_dns_name_concat_one("", "", 0, "."); + test_dns_name_concat_one(".", "", 0, "."); + test_dns_name_concat_one("", ".", 0, "."); + test_dns_name_concat_one(".", ".", 0, "."); + test_dns_name_concat_one("foo", "bar", 0, "foo.bar"); + test_dns_name_concat_one("foo.foo", "bar.bar", 0, "foo.foo.bar.bar"); + test_dns_name_concat_one("foo", NULL, 0, "foo"); + test_dns_name_concat_one("foo", ".", 0, "foo"); + test_dns_name_concat_one("foo.", "bar.", 0, "foo.bar"); + test_dns_name_concat_one(NULL, NULL, 0, "."); + test_dns_name_concat_one(NULL, ".", 0, "."); + test_dns_name_concat_one(NULL, "foo", 0, "foo"); +} + +static void test_dns_name_is_valid_one(const char *s, int ret) { + assert_se(dns_name_is_valid(s) == ret); +} + +static void test_dns_name_is_valid(void) { + test_dns_name_is_valid_one("foo", 1); + test_dns_name_is_valid_one("foo.", 1); + test_dns_name_is_valid_one("foo..", 0); + test_dns_name_is_valid_one("Foo", 1); + test_dns_name_is_valid_one("foo.bar", 1); + test_dns_name_is_valid_one("foo.bar.baz", 1); + test_dns_name_is_valid_one("", 1); + test_dns_name_is_valid_one("foo..bar", 0); + test_dns_name_is_valid_one(".foo.bar", 0); + test_dns_name_is_valid_one("foo.bar.", 1); + test_dns_name_is_valid_one("foo.bar..", 0); + test_dns_name_is_valid_one("\\zbar", 0); + test_dns_name_is_valid_one("ä", 1); + test_dns_name_is_valid_one("\n", 0); + + /* 256 characters*/ + test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345", 0); + + /* 255 characters*/ + test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a1234", 0); + + /* 254 characters*/ + test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a123", 0); + + /* 253 characters*/ + test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12", 1); + + /* label of 64 chars length */ + test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a123", 0); + + /* label of 63 chars length */ + test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a12", 1); +} + +static void test_dns_service_name_is_valid(void) { + assert_se(dns_service_name_is_valid("Lennart's Compüter")); + assert_se(dns_service_name_is_valid("piff.paff")); + + assert_se(!dns_service_name_is_valid(NULL)); + assert_se(!dns_service_name_is_valid("")); + assert_se(!dns_service_name_is_valid("foo\nbar")); + assert_se(!dns_service_name_is_valid("foo\201bar")); + assert_se(!dns_service_name_is_valid("this is an overly long string that is certainly longer than 63 characters")); +} + +static void test_dns_srv_type_is_valid(void) { + + assert_se(dns_srv_type_is_valid("_http._tcp")); + assert_se(dns_srv_type_is_valid("_foo-bar._tcp")); + assert_se(dns_srv_type_is_valid("_w._udp")); + assert_se(dns_srv_type_is_valid("_a800._tcp")); + assert_se(dns_srv_type_is_valid("_a-800._tcp")); + + assert_se(!dns_srv_type_is_valid(NULL)); + assert_se(!dns_srv_type_is_valid("")); + assert_se(!dns_srv_type_is_valid("x")); + assert_se(!dns_srv_type_is_valid("_foo")); + assert_se(!dns_srv_type_is_valid("_tcp")); + assert_se(!dns_srv_type_is_valid("_")); + assert_se(!dns_srv_type_is_valid("_foo.")); + assert_se(!dns_srv_type_is_valid("_föo._tcp")); + assert_se(!dns_srv_type_is_valid("_f\no._tcp")); + assert_se(!dns_srv_type_is_valid("_800._tcp")); + assert_se(!dns_srv_type_is_valid("_-800._tcp")); + assert_se(!dns_srv_type_is_valid("_-foo._tcp")); + assert_se(!dns_srv_type_is_valid("_piep._foo._udp")); +} + +static void test_dns_service_join_one(const char *a, const char *b, const char *c, int r, const char *d) { + _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *t = NULL; + + assert_se(dns_service_join(a, b, c, &t) == r); + assert_se(streq_ptr(t, d)); + + if (r < 0) + return; + + assert_se(dns_service_split(t, &x, &y, &z) >= 0); + assert_se(streq_ptr(a, x)); + assert_se(streq_ptr(b, y)); + assert_se(dns_name_equal(c, z) > 0); +} + +static void test_dns_service_join(void) { + test_dns_service_join_one("", "", "", -EINVAL, NULL); + test_dns_service_join_one("", "_http._tcp", "", -EINVAL, NULL); + test_dns_service_join_one("", "_http._tcp", "foo", -EINVAL, NULL); + test_dns_service_join_one("foo", "", "foo", -EINVAL, NULL); + test_dns_service_join_one("foo", "foo", "foo", -EINVAL, NULL); + + test_dns_service_join_one("foo", "_http._tcp", "", 0, "foo._http._tcp"); + test_dns_service_join_one(NULL, "_http._tcp", "", 0, "_http._tcp"); + test_dns_service_join_one("foo", "_http._tcp", "foo", 0, "foo._http._tcp.foo"); + test_dns_service_join_one(NULL, "_http._tcp", "foo", 0, "_http._tcp.foo"); + test_dns_service_join_one("Lennart's PC", "_pc._tcp", "foo.bar.com", 0, "Lennart\\039s\\032PC._pc._tcp.foo.bar.com"); + test_dns_service_join_one(NULL, "_pc._tcp", "foo.bar.com", 0, "_pc._tcp.foo.bar.com"); +} + +static void test_dns_service_split_one(const char *joined, const char *a, const char *b, const char *c, int r) { + _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *t = NULL; + + assert_se(dns_service_split(joined, &x, &y, &z) == r); + assert_se(streq_ptr(x, a)); + assert_se(streq_ptr(y, b)); + assert_se(streq_ptr(z, c)); + + if (r < 0) + return; + + if (y) { + assert_se(dns_service_join(x, y, z, &t) == 0); + assert_se(dns_name_equal(joined, t) > 0); + } else + assert_se(!x && dns_name_equal(z, joined) > 0); +} + +static void test_dns_service_split(void) { + test_dns_service_split_one("", NULL, NULL, ".", 0); + test_dns_service_split_one("foo", NULL, NULL, "foo", 0); + test_dns_service_split_one("foo.bar", NULL, NULL, "foo.bar", 0); + test_dns_service_split_one("_foo.bar", NULL, NULL, "_foo.bar", 0); + test_dns_service_split_one("_foo._bar", NULL, "_foo._bar", ".", 0); + test_dns_service_split_one("_meh._foo._bar", "_meh", "_foo._bar", ".", 0); + test_dns_service_split_one("Wuff\\032Wuff._foo._bar.waldo.com", "Wuff Wuff", "_foo._bar", "waldo.com", 0); +} + +static void test_dns_name_change_suffix_one(const char *name, const char *old_suffix, const char *new_suffix, int r, const char *result) { + _cleanup_free_ char *s = NULL; + + assert_se(dns_name_change_suffix(name, old_suffix, new_suffix, &s) == r); + assert_se(streq_ptr(s, result)); +} + +static void test_dns_name_change_suffix(void) { + test_dns_name_change_suffix_one("foo.bar", "bar", "waldo", 1, "foo.waldo"); + test_dns_name_change_suffix_one("foo.bar.waldi.quux", "foo.bar.waldi.quux", "piff.paff", 1, "piff.paff"); + test_dns_name_change_suffix_one("foo.bar.waldi.quux", "bar.waldi.quux", "piff.paff", 1, "foo.piff.paff"); + test_dns_name_change_suffix_one("foo.bar.waldi.quux", "waldi.quux", "piff.paff", 1, "foo.bar.piff.paff"); + test_dns_name_change_suffix_one("foo.bar.waldi.quux", "quux", "piff.paff", 1, "foo.bar.waldi.piff.paff"); + test_dns_name_change_suffix_one("foo.bar.waldi.quux", "", "piff.paff", 1, "foo.bar.waldi.quux.piff.paff"); + test_dns_name_change_suffix_one("", "", "piff.paff", 1, "piff.paff"); + test_dns_name_change_suffix_one("", "", "", 1, "."); + test_dns_name_change_suffix_one("a", "b", "c", 0, NULL); +} + +static void test_dns_name_suffix_one(const char *name, unsigned n_labels, const char *result, int ret) { + const char *p = NULL; + + assert_se(ret == dns_name_suffix(name, n_labels, &p)); + assert_se(streq_ptr(p, result)); +} + +static void test_dns_name_suffix(void) { + test_dns_name_suffix_one("foo.bar", 2, "foo.bar", 0); + test_dns_name_suffix_one("foo.bar", 1, "bar", 1); + test_dns_name_suffix_one("foo.bar", 0, "", 2); + test_dns_name_suffix_one("foo.bar", 3, NULL, -EINVAL); + test_dns_name_suffix_one("foo.bar", 4, NULL, -EINVAL); + + test_dns_name_suffix_one("bar", 1, "bar", 0); + test_dns_name_suffix_one("bar", 0, "", 1); + test_dns_name_suffix_one("bar", 2, NULL, -EINVAL); + test_dns_name_suffix_one("bar", 3, NULL, -EINVAL); + + test_dns_name_suffix_one("", 0, "", 0); + test_dns_name_suffix_one("", 1, NULL, -EINVAL); + test_dns_name_suffix_one("", 2, NULL, -EINVAL); +} + +static void test_dns_name_count_labels_one(const char *name, int n) { + assert_se(dns_name_count_labels(name) == n); +} + +static void test_dns_name_count_labels(void) { + test_dns_name_count_labels_one("foo.bar.quux.", 3); + test_dns_name_count_labels_one("foo.bar.quux", 3); + test_dns_name_count_labels_one("foo.bar.", 2); + test_dns_name_count_labels_one("foo.bar", 2); + test_dns_name_count_labels_one("foo.", 1); + test_dns_name_count_labels_one("foo", 1); + test_dns_name_count_labels_one("", 0); + test_dns_name_count_labels_one(".", 0); + test_dns_name_count_labels_one("..", -EINVAL); +} + +static void test_dns_name_equal_skip_one(const char *a, unsigned n_labels, const char *b, int ret) { + assert_se(dns_name_equal_skip(a, n_labels, b) == ret); +} + +static void test_dns_name_equal_skip(void) { + test_dns_name_equal_skip_one("foo", 0, "bar", 0); + test_dns_name_equal_skip_one("foo", 0, "foo", 1); + test_dns_name_equal_skip_one("foo", 1, "foo", 0); + test_dns_name_equal_skip_one("foo", 2, "foo", 0); + + test_dns_name_equal_skip_one("foo.bar", 0, "foo.bar", 1); + test_dns_name_equal_skip_one("foo.bar", 1, "foo.bar", 0); + test_dns_name_equal_skip_one("foo.bar", 2, "foo.bar", 0); + test_dns_name_equal_skip_one("foo.bar", 3, "foo.bar", 0); + + test_dns_name_equal_skip_one("foo.bar", 0, "bar", 0); + test_dns_name_equal_skip_one("foo.bar", 1, "bar", 1); + test_dns_name_equal_skip_one("foo.bar", 2, "bar", 0); + test_dns_name_equal_skip_one("foo.bar", 3, "bar", 0); + + test_dns_name_equal_skip_one("foo.bar", 0, "", 0); + test_dns_name_equal_skip_one("foo.bar", 1, "", 0); + test_dns_name_equal_skip_one("foo.bar", 2, "", 1); + test_dns_name_equal_skip_one("foo.bar", 3, "", 0); + + test_dns_name_equal_skip_one("", 0, "", 1); + test_dns_name_equal_skip_one("", 1, "", 0); + test_dns_name_equal_skip_one("", 1, "foo", 0); + test_dns_name_equal_skip_one("", 2, "foo", 0); +} + +static void test_dns_name_compare_func(void) { + assert_se(dns_name_compare_func("", "") == 0); + assert_se(dns_name_compare_func("", ".") == 0); + assert_se(dns_name_compare_func(".", "") == 0); + assert_se(dns_name_compare_func("foo", "foo.") == 0); + assert_se(dns_name_compare_func("foo.", "foo") == 0); + assert_se(dns_name_compare_func("foo", "foo") == 0); + assert_se(dns_name_compare_func("foo.", "foo.") == 0); + assert_se(dns_name_compare_func("heise.de", "HEISE.DE.") == 0); + + assert_se(dns_name_compare_func("de.", "heise.de") != 0); +} + +static void test_dns_name_common_suffix_one(const char *a, const char *b, const char *result) { + const char *c; + + assert_se(dns_name_common_suffix(a, b, &c) >= 0); + assert_se(streq(c, result)); +} + +static void test_dns_name_common_suffix(void) { + test_dns_name_common_suffix_one("", "", ""); + test_dns_name_common_suffix_one("foo", "", ""); + test_dns_name_common_suffix_one("", "foo", ""); + test_dns_name_common_suffix_one("foo", "bar", ""); + test_dns_name_common_suffix_one("bar", "foo", ""); + test_dns_name_common_suffix_one("foo", "foo", "foo"); + test_dns_name_common_suffix_one("quux.foo", "foo", "foo"); + test_dns_name_common_suffix_one("foo", "quux.foo", "foo"); + test_dns_name_common_suffix_one("this.is.a.short.sentence", "this.is.another.short.sentence", "short.sentence"); + test_dns_name_common_suffix_one("FOO.BAR", "tEST.bAR", "BAR"); +} + +static void test_dns_name_apply_idna_one(const char *s, const char *result) { +#ifdef HAVE_LIBIDN + _cleanup_free_ char *buf = NULL; + assert_se(dns_name_apply_idna(s, &buf) >= 0); + assert_se(dns_name_equal(buf, result) > 0); +#endif +} + +static void test_dns_name_apply_idna(void) { + test_dns_name_apply_idna_one("", ""); + test_dns_name_apply_idna_one("foo", "foo"); + test_dns_name_apply_idna_one("foo.", "foo"); + test_dns_name_apply_idna_one("foo.bar", "foo.bar"); + test_dns_name_apply_idna_one("foo.bar.", "foo.bar"); + test_dns_name_apply_idna_one("föö", "xn--f-1gaa"); + test_dns_name_apply_idna_one("föö.", "xn--f-1gaa"); + test_dns_name_apply_idna_one("föö.bär", "xn--f-1gaa.xn--br-via"); + test_dns_name_apply_idna_one("föö.bär.", "xn--f-1gaa.xn--br-via"); } int main(int argc, char *argv[]) { test_dns_label_unescape(); + test_dns_label_unescape_suffix(); test_dns_label_escape(); test_dns_name_normalize(); test_dns_name_equal(); test_dns_name_endswith(); - test_dns_name_root(); - test_dns_name_single_label(); + test_dns_name_startswith(); + test_dns_name_between(); + test_dns_name_is_root(); + test_dns_name_is_single_label(); test_dns_name_reverse(); + test_dns_name_concat(); + test_dns_name_is_valid(); + test_dns_name_to_wire_format(); + test_dns_service_name_is_valid(); + test_dns_srv_type_is_valid(); + test_dns_service_join(); + test_dns_service_split(); + test_dns_name_change_suffix(); + test_dns_name_suffix(); + test_dns_name_count_labels(); + test_dns_name_equal_skip(); + test_dns_name_compare_func(); + test_dns_name_common_suffix(); + test_dns_name_apply_idna(); return 0; } diff --git a/src/test/test-ellipsize.c b/src/test/test-ellipsize.c index 27df9089c3..d4f09b08a5 100644 --- a/src/test/test-ellipsize.c +++ b/src/test/test-ellipsize.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,9 +19,11 @@ #include <stdio.h> -#include "util.h" -#include "terminal-util.h" +#include "alloc-util.h" #include "def.h" +#include "string-util.h" +#include "terminal-util.h" +#include "util.h" static void test_one(const char *p) { _cleanup_free_ char *t; diff --git a/src/test/test-engine.c b/src/test/test-engine.c index a7ab21a415..a651f6b683 100644 --- a/src/test/test-engine.c +++ b/src/test/test-engine.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,15 +17,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <errno.h> +#include <stdio.h> #include <string.h> -#include "manager.h" #include "bus-util.h" +#include "manager.h" +#include "rm-rf.h" +#include "test-helper.h" +#include "tests.h" int main(int argc, char *argv[]) { - _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL; + _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL; Manager *m = NULL; Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL; FILE *serial = NULL; @@ -35,11 +37,13 @@ int main(int argc, char *argv[]) { Job *j; int r; + assert_se(runtime_dir = setup_fake_runtime_dir()); + /* prepare the test */ assert_se(set_unit_path(TEST_DIR) >= 0); - r = manager_new(MANAGER_USER, true, &m); - if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) { - printf("Skipping test: manager_new: %s", strerror(-r)); + r = manager_new(UNIT_FILE_USER, true, &m); + if (MANAGER_SKIP_TEST(r)) { + log_notice_errno(r, "Skipping test: manager_new: %m"); return EXIT_TEST_SKIP; } assert_se(r >= 0); @@ -52,7 +56,7 @@ int main(int argc, char *argv[]) { manager_dump_units(m, stdout, "\t"); printf("Test1: (Trivial)\n"); - r = manager_add_job(m, JOB_START, c, JOB_REPLACE, false, &err, &j); + r = manager_add_job(m, JOB_START, c, JOB_REPLACE, &err, &j); if (sd_bus_error_is_set(&err)) log_error("error: %s: %s", err.name, err.message); assert_se(r == 0); @@ -65,15 +69,15 @@ int main(int argc, char *argv[]) { manager_dump_units(m, stdout, "\t"); printf("Test2: (Cyclic Order, Unfixable)\n"); - assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, false, NULL, &j) == -EDEADLK); + assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, NULL, &j) == -EDEADLK); manager_dump_jobs(m, stdout, "\t"); printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n"); - assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, false, NULL, &j) == 0); + assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, NULL, &j) == 0); manager_dump_jobs(m, stdout, "\t"); printf("Test4: (Identical transaction)\n"); - assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, false, NULL, &j) == 0); + assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, NULL, &j) == 0); manager_dump_jobs(m, stdout, "\t"); printf("Load3:\n"); @@ -81,21 +85,21 @@ int main(int argc, char *argv[]) { manager_dump_units(m, stdout, "\t"); printf("Test5: (Colliding transaction, fail)\n"); - assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, false, NULL, &j) == -EDEADLK); + assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, NULL, &j) == -EDEADLK); printf("Test6: (Colliding transaction, replace)\n"); - assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, false, NULL, &j) == 0); + assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, NULL, &j) == 0); manager_dump_jobs(m, stdout, "\t"); printf("Test7: (Unmergeable job type, fail)\n"); - assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, false, NULL, &j) == -EDEADLK); + assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, NULL, &j) == -EDEADLK); printf("Test8: (Mergeable job type, fail)\n"); - assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, false, NULL, &j) == 0); + assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, NULL, &j) == 0); manager_dump_jobs(m, stdout, "\t"); printf("Test9: (Unmergeable job type, replace)\n"); - assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, false, NULL, &j) == 0); + assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, NULL, &j) == 0); manager_dump_jobs(m, stdout, "\t"); printf("Load4:\n"); @@ -103,7 +107,7 @@ int main(int argc, char *argv[]) { manager_dump_units(m, stdout, "\t"); printf("Test10: (Unmergeable job type of auxiliary job, fail)\n"); - assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, false, NULL, &j) == 0); + assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, &j) == 0); manager_dump_jobs(m, stdout, "\t"); manager_free(m); diff --git a/src/test/test-env-replace.c b/src/test/test-env-util.c index 2e28c0c49b..35bb62906e 100644 --- a/src/test/test-env-replace.c +++ b/src/test/test-env-util.c @@ -1,9 +1,8 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. Copyright 2010 Lennart Poettering + Copyright 2016 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 @@ -21,9 +20,10 @@ #include <string.h> -#include "util.h" -#include "strv.h" #include "env-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" static void test_strv_env_delete(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL; @@ -118,6 +118,8 @@ static void test_replace_env_arg(void) { "$FOO$FOO", "${FOO}${BAR}", "${FOO", + "FOO$$${FOO}", + "$$FOO${FOO}", NULL }; _cleanup_strv_free_ char **r = NULL; @@ -133,7 +135,9 @@ static void test_replace_env_arg(void) { assert_se(streq(r[6], "BAR")); assert_se(streq(r[7], "BAR BARwaldo")); assert_se(streq(r[8], "${FOO")); - assert_se(strv_length(r) == 9); + assert_se(streq(r[9], "FOO$BAR BAR")); + assert_se(streq(r[10], "$FOOBAR BAR")); + assert_se(strv_length(r) == 11); } static void test_env_clean(void) { @@ -174,10 +178,37 @@ static void test_env_name_is_valid(void) { assert_se(!env_name_is_valid(NULL)); assert_se(!env_name_is_valid("")); + assert_se(!env_name_is_valid("xxx\a")); + assert_se(!env_name_is_valid("xxx\007b")); + assert_se(!env_name_is_valid("\007\009")); assert_se(!env_name_is_valid("5_starting_with_a_number_is_wrong")); assert_se(!env_name_is_valid("#¤%&?_only_numbers_letters_and_underscore_allowed")); } +static void test_env_value_is_valid(void) { + assert_se(env_value_is_valid("")); + assert_se(env_value_is_valid("głąb kapuściany")); + assert_se(env_value_is_valid("printf \"\\x1b]0;<mock-chroot>\\x07<mock-chroot>\"")); +} + +static void test_env_assignment_is_valid(void) { + assert_se(env_assignment_is_valid("a=")); + assert_se(env_assignment_is_valid("b=głąb kapuściany")); + assert_se(env_assignment_is_valid("c=\\007\\009\\011")); + assert_se(env_assignment_is_valid("e=printf \"\\x1b]0;<mock-chroot>\\x07<mock-chroot>\"")); + + assert_se(!env_assignment_is_valid("=")); + assert_se(!env_assignment_is_valid("a b=")); + assert_se(!env_assignment_is_valid("a =")); + assert_se(!env_assignment_is_valid(" b=")); + /* no dots or dashes: http://tldp.org/LDP/abs/html/gotchas.html */ + assert_se(!env_assignment_is_valid("a.b=")); + assert_se(!env_assignment_is_valid("a-b=")); + assert_se(!env_assignment_is_valid("\007=głąb kapuściany")); + assert_se(!env_assignment_is_valid("c\009=\007\009\011")); + assert_se(!env_assignment_is_valid("głąb=printf \"\x1b]0;<mock-chroot>\x07<mock-chroot>\"")); +} + int main(int argc, char *argv[]) { test_strv_env_delete(); test_strv_env_unset(); @@ -186,6 +217,8 @@ int main(int argc, char *argv[]) { test_replace_env_arg(); test_env_clean(); test_env_name_is_valid(); + test_env_value_is_valid(); + test_env_assignment_is_valid(); return 0; } diff --git a/src/test/test-escape.c b/src/test/test-escape.c new file mode 100644 index 0000000000..6cbb8443fe --- /dev/null +++ b/src/test/test-escape.c @@ -0,0 +1,114 @@ +/*** + This file is part of systemd. + + Copyright 2010 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 "alloc-util.h" +#include "escape.h" +#include "macro.h" + +static void test_cescape(void) { + _cleanup_free_ char *escaped; + + assert_se(escaped = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313")); + assert_se(streq(escaped, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313")); +} + +static void test_cunescape(void) { + _cleanup_free_ char *unescaped; + + assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", 0, &unescaped) < 0); + assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00")); + unescaped = mfree(unescaped); + + /* incomplete sequences */ + assert_se(cunescape("\\x0", 0, &unescaped) < 0); + assert_se(cunescape("\\x0", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\x0")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\x", 0, &unescaped) < 0); + assert_se(cunescape("\\x", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\x")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\", 0, &unescaped) < 0); + assert_se(cunescape("\\", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\11", 0, &unescaped) < 0); + assert_se(cunescape("\\11", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\11")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\1", 0, &unescaped) < 0); + assert_se(cunescape("\\1", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\1")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\u0000", 0, &unescaped) < 0); + assert_se(cunescape("\\u00DF\\U000000df\\u03a0\\U00000041", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "ßßΠA")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\073", 0, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, ";")); +} + +static void test_shell_escape_one(const char *s, const char *bad, const char *expected) { + _cleanup_free_ char *r; + + assert_se(r = shell_escape(s, bad)); + assert_se(streq_ptr(r, expected)); +} + +static void test_shell_escape(void) { + test_shell_escape_one("", "", ""); + test_shell_escape_one("\\", "", "\\\\"); + test_shell_escape_one("foobar", "", "foobar"); + test_shell_escape_one("foobar", "o", "f\\o\\obar"); + test_shell_escape_one("foo:bar,baz", ",:", "foo\\:bar\\,baz"); +} + +static void test_shell_maybe_quote_one(const char *s, const char *expected) { + _cleanup_free_ char *r; + + assert_se(r = shell_maybe_quote(s)); + assert_se(streq(r, expected)); +} + +static void test_shell_maybe_quote(void) { + + test_shell_maybe_quote_one("", ""); + test_shell_maybe_quote_one("\\", "\"\\\\\""); + test_shell_maybe_quote_one("\"", "\"\\\"\""); + test_shell_maybe_quote_one("foobar", "foobar"); + test_shell_maybe_quote_one("foo bar", "\"foo bar\""); + test_shell_maybe_quote_one("foo \"bar\" waldo", "\"foo \\\"bar\\\" waldo\""); + test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\""); +} + +int main(int argc, char *argv[]) { + test_cescape(); + test_cunescape(); + test_shell_escape(); + test_shell_maybe_quote(); + + return 0; +} diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 0f4172e722..8b4ff22495 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -17,14 +17,26 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <grp.h> +#include <pwd.h> #include <stdio.h> +#include <sys/prctl.h> +#include <sys/types.h> -#include "unit.h" -#include "manager.h" -#include "util.h" +#include "fileio.h" +#include "fs-util.h" #include "macro.h" +#include "manager.h" #include "mkdir.h" +#include "path-util.h" #include "rm-rf.h" +#ifdef HAVE_SECCOMP +#include "seccomp-util.h" +#endif +#include "test-helper.h" +#include "unit.h" +#include "util.h" +#include "virt.h" typedef void (*test_function_t)(Manager *m); @@ -77,10 +89,24 @@ static void test_exec_workingdirectory(Manager *m) { } static void test_exec_personality(Manager *m) { - test(m, "exec-personality-x86.service", 0, CLD_EXITED); - #if defined(__x86_64__) test(m, "exec-personality-x86-64.service", 0, CLD_EXITED); + +#elif defined(__s390__) + test(m, "exec-personality-s390.service", 0, CLD_EXITED); + +#elif defined(__powerpc64__) +# if __BYTE_ORDER == __BIG_ENDIAN + test(m, "exec-personality-ppc64.service", 0, CLD_EXITED); +# else + test(m, "exec-personality-ppc64le.service", 0, CLD_EXITED); +# endif + +#elif defined(__aarch64__) + test(m, "exec-personality-aarch64.service", 0, CLD_EXITED); + +#elif defined(__i386__) + test(m, "exec-personality-x86.service", 0, CLD_EXITED); #endif } @@ -99,31 +125,84 @@ static void test_exec_privatetmp(Manager *m) { } static void test_exec_privatedevices(Manager *m) { + if (detect_container() > 0) { + log_notice("testing in container, skipping private device tests"); + return; + } test(m, "exec-privatedevices-yes.service", 0, CLD_EXITED); test(m, "exec-privatedevices-no.service", 0, CLD_EXITED); } +static void test_exec_privatedevices_capabilities(Manager *m) { + if (detect_container() > 0) { + log_notice("testing in container, skipping private device tests"); + return; + } + test(m, "exec-privatedevices-yes-capability-mknod.service", 0, CLD_EXITED); + test(m, "exec-privatedevices-no-capability-mknod.service", 0, CLD_EXITED); +} + +static void test_exec_readonlypaths(Manager *m) { + test(m, "exec-readonlypaths.service", 0, CLD_EXITED); + test(m, "exec-readonlypaths-mount-propagation.service", 0, CLD_EXITED); +} + +static void test_exec_readwritepaths(Manager *m) { + test(m, "exec-readwritepaths-mount-propagation.service", 0, CLD_EXITED); +} + +static void test_exec_inaccessiblepaths(Manager *m) { + test(m, "exec-inaccessiblepaths-mount-propagation.service", 0, CLD_EXITED); +} + static void test_exec_systemcallfilter(Manager *m) { #ifdef HAVE_SECCOMP + if (!is_seccomp_available()) + return; test(m, "exec-systemcallfilter-not-failing.service", 0, CLD_EXITED); test(m, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED); test(m, "exec-systemcallfilter-failing.service", SIGSYS, CLD_KILLED); test(m, "exec-systemcallfilter-failing2.service", SIGSYS, CLD_KILLED); + #endif } static void test_exec_systemcallerrornumber(Manager *m) { #ifdef HAVE_SECCOMP - test(m, "exec-systemcallerrornumber.service", 1, CLD_EXITED); + if (is_seccomp_available()) + test(m, "exec-systemcallerrornumber.service", 1, CLD_EXITED); +#endif +} + +static void test_exec_systemcall_system_mode_with_user(Manager *m) { +#ifdef HAVE_SECCOMP + if (!is_seccomp_available()) + return; + if (getpwnam("nobody")) + test(m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED); + else if (getpwnam("nfsnobody")) + test(m, "exec-systemcallfilter-system-user-nfsnobody.service", 0, CLD_EXITED); + else + log_error_errno(errno, "Skipping test_exec_systemcall_system_mode_with_user, could not find nobody/nfsnobody user: %m"); #endif } static void test_exec_user(Manager *m) { - test(m, "exec-user.service", 0, CLD_EXITED); + if (getpwnam("nobody")) + test(m, "exec-user.service", 0, CLD_EXITED); + else if (getpwnam("nfsnobody")) + test(m, "exec-user-nfsnobody.service", 0, CLD_EXITED); + else + log_error_errno(errno, "Skipping test_exec_user, could not find nobody/nfsnobody user: %m"); } static void test_exec_group(Manager *m) { - test(m, "exec-group.service", 0, CLD_EXITED); + if (getgrnam("nobody")) + test(m, "exec-group.service", 0, CLD_EXITED); + else if (getgrnam("nfsnobody")) + test(m, "exec-group-nfsnobody.service", 0, CLD_EXITED); + else + log_error_errno(errno, "Skipping test_exec_group, could not find nobody/nfsnobody group: %m"); } static void test_exec_environment(Manager *m) { @@ -132,28 +211,187 @@ static void test_exec_environment(Manager *m) { test(m, "exec-environment-empty.service", 0, CLD_EXITED); } +static void test_exec_environmentfile(Manager *m) { + static const char e[] = + "VAR1='word1 word2'\n" + "VAR2=word3 \n" + "# comment1\n" + "\n" + "; comment2\n" + " ; # comment3\n" + "line without an equal\n" + "VAR3='$word 5 6'\n"; + int r; + + r = write_string_file("/tmp/test-exec_environmentfile.conf", e, WRITE_STRING_FILE_CREATE); + assert_se(r == 0); + + test(m, "exec-environmentfile.service", 0, CLD_EXITED); + + unlink("/tmp/test-exec_environmentfile.conf"); +} + +static void test_exec_passenvironment(Manager *m) { + /* test-execute runs under MANAGER_USER which, by default, forwards all + * variables present in the environment, but only those that are + * present _at the time it is created_! + * + * So these PassEnvironment checks are still expected to work, since we + * are ensuring the variables are not present at manager creation (they + * are unset explicitly in main) and are only set here. + * + * This is still a good approximation of how a test for MANAGER_SYSTEM + * would work. + */ + assert_se(setenv("VAR1", "word1 word2", 1) == 0); + assert_se(setenv("VAR2", "word3", 1) == 0); + assert_se(setenv("VAR3", "$word 5 6", 1) == 0); + test(m, "exec-passenvironment.service", 0, CLD_EXITED); + test(m, "exec-passenvironment-repeated.service", 0, CLD_EXITED); + test(m, "exec-passenvironment-empty.service", 0, CLD_EXITED); + assert_se(unsetenv("VAR1") == 0); + assert_se(unsetenv("VAR2") == 0); + assert_se(unsetenv("VAR3") == 0); + test(m, "exec-passenvironment-absent.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); } +static void test_exec_runtimedirectory(Manager *m) { + test(m, "exec-runtimedirectory.service", 0, CLD_EXITED); + test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED); + if (getgrnam("nobody")) + test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED); + else if (getgrnam("nfsnobody")) + test(m, "exec-runtimedirectory-owner-nfsnobody.service", 0, CLD_EXITED); + else + log_error_errno(errno, "Skipping test_exec_runtimedirectory-owner, could not find nobody/nfsnobody group: %m"); +} + +static void test_exec_capabilityboundingset(Manager *m) { + int r; + + /* We use capsh to test if the capabilities are + * properly set, so be sure that it exists */ + r = find_binary("capsh", NULL); + if (r < 0) { + log_error_errno(r, "Skipping test_exec_capabilityboundingset, could not find capsh binary: %m"); + return; + } + + test(m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED); + test(m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED); + test(m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED); + test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED); +} + +static void test_exec_capabilityambientset(Manager *m) { + int r; + + /* Check if the kernel has support for ambient capabilities. Run + * the tests only if that's the case. Clearing all ambient + * capabilities is fine, since we are expecting them to be unset + * in the first place for the tests. */ + r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0); + if (r >= 0 || errno != EINVAL) { + if (getpwnam("nobody")) { + test(m, "exec-capabilityambientset.service", 0, CLD_EXITED); + test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED); + } else if (getpwnam("nfsnobody")) { + test(m, "exec-capabilityambientset-nfsnobody.service", 0, CLD_EXITED); + test(m, "exec-capabilityambientset-merge-nfsnobody.service", 0, CLD_EXITED); + } else + log_error_errno(errno, "Skipping test_exec_capabilityambientset, could not find nobody/nfsnobody user: %m"); + } else + log_error_errno(errno, "Skipping test_exec_capabilityambientset, the kernel does not support ambient capabilities: %m"); +} + +static void test_exec_privatenetwork(Manager *m) { + int r; + + r = find_binary("ip", NULL); + if (r < 0) { + log_error_errno(r, "Skipping test_exec_privatenetwork, could not find ip binary: %m"); + return; + } + + test(m, "exec-privatenetwork-yes.service", 0, CLD_EXITED); +} + +static void test_exec_oomscoreadjust(Manager *m) { + test(m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED); + test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED); +} + +static void test_exec_ioschedulingclass(Manager *m) { + test(m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED); + test(m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED); + test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED); + test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED); +} + +static void test_exec_spec_interpolation(Manager *m) { + test(m, "exec-spec-interpolation.service", 0, CLD_EXITED); +} + +static int run_tests(UnitFileScope scope, test_function_t *tests) { + test_function_t *test = NULL; + Manager *m = NULL; + int r; + + assert_se(tests); + + r = manager_new(scope, true, &m); + if (MANAGER_SKIP_TEST(r)) { + log_notice_errno(r, "Skipping test: manager_new: %m"); + return EXIT_TEST_SKIP; + } + assert_se(r >= 0); + assert_se(manager_startup(m, NULL, NULL) >= 0); + + for (test = tests; test && *test; test++) + (*test)(m); + + manager_free(m); + + return 0; +} + int main(int argc, char *argv[]) { - test_function_t tests[] = { + test_function_t user_tests[] = { test_exec_workingdirectory, test_exec_personality, test_exec_ignoresigpipe, test_exec_privatetmp, test_exec_privatedevices, + test_exec_privatedevices_capabilities, + test_exec_readonlypaths, + test_exec_readwritepaths, + test_exec_inaccessiblepaths, + test_exec_privatenetwork, test_exec_systemcallfilter, test_exec_systemcallerrornumber, test_exec_user, test_exec_group, test_exec_environment, + test_exec_environmentfile, + test_exec_passenvironment, test_exec_umask, + test_exec_runtimedirectory, + test_exec_capabilityboundingset, + test_exec_capabilityambientset, + test_exec_oomscoreadjust, + test_exec_ioschedulingclass, + test_exec_spec_interpolation, + NULL, + }; + test_function_t system_tests[] = { + test_exec_systemcall_system_mode_with_user, NULL, }; - test_function_t *test = NULL; - Manager *m = NULL; int r; log_parse_environment(); @@ -165,20 +403,22 @@ int main(int argc, char *argv[]) { return EXIT_TEST_SKIP; } - assert_se(set_unit_path(TEST_DIR) >= 0); + assert_se(setenv("XDG_RUNTIME_DIR", "/tmp/", 1) == 0); + assert_se(set_unit_path(TEST_DIR "/test-execute/") >= 0); - r = manager_new(MANAGER_USER, true, &m); - if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) { - printf("Skipping test: manager_new: %s", strerror(-r)); - return EXIT_TEST_SKIP; - } - assert_se(r >= 0); - assert_se(manager_startup(m, NULL, NULL) >= 0); + /* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test + * cases, otherwise (and if they are present in the environment), + * `manager_default_environment` will copy them into the default + * environment which is passed to each created job, which will make the + * tests that expect those not to be present to fail. + */ + assert_se(unsetenv("VAR1") == 0); + assert_se(unsetenv("VAR2") == 0); + assert_se(unsetenv("VAR3") == 0); - for (test = tests; test && *test; test++) - (*test)(m); + r = run_tests(UNIT_FILE_USER, user_tests); + if (r != 0) + return r; - manager_free(m); - - return 0; + return run_tests(UNIT_FILE_SYSTEM, system_tests); } diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c new file mode 100644 index 0000000000..7a23fa7b7b --- /dev/null +++ b/src/test/test-extract-word.c @@ -0,0 +1,556 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2013 Thomas H.P. Andersen + + 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 <string.h> + +#include "extract-word.h" +#include "log.h" +#include "string-util.h" + +static void test_extract_first_word(void) { + const char *p, *original; + char *t; + + p = original = "foobar waldo"; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(p == original + 7); + + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, NULL, 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\"foobar\" \'waldo\'"; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "\"foobar\"")); + free(t); + assert_se(p == original + 9); + + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "\'waldo\'")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, NULL, 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\"foobar\" \'waldo\'"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(p == original + 9); + + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, NULL, 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\""; + assert_se(extract_first_word(&p, &t, NULL, 0) == 1); + assert_se(streq(t, "\"")); + free(t); + assert_se(isempty(p)); + + p = original = "\""; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\'"; + assert_se(extract_first_word(&p, &t, NULL, 0) == 1); + assert_se(streq(t, "\'")); + free(t); + assert_se(isempty(p)); + + p = original = "\'"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\'fooo"; + assert_se(extract_first_word(&p, &t, NULL, 0) == 1); + assert_se(streq(t, "\'fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "\'fooo"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\'fooo"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "\"fooo"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "yay\'foo\'bar"; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "yay\'foo\'bar")); + free(t); + assert_se(isempty(p)); + + p = original = "yay\'foo\'bar"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "yayfoobar")); + free(t); + assert_se(isempty(p)); + + p = original = " foobar "; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(isempty(p)); + + p = original = " foo\\ba\\x6ar "; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0); + assert_se(streq(t, "foo\ba\x6ar")); + free(t); + assert_se(isempty(p)); + + p = original = " foo\\ba\\x6ar "; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "foobax6ar")); + free(t); + assert_se(isempty(p)); + + p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0); + assert_se(streq(t, "föo")); + free(t); + assert_se(p == original + 13); + + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE) > 0); + assert_se(streq(t, "pi\360\237\222\251le")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); + assert_se(streq(t, "foo")); + free(t); + assert_se(isempty(p)); + + p = original = "foo::bar"; + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "foo")); + free(t); + assert_se(p == original + 5); + + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "bar")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, ":", 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "foo\\:bar::waldo"; + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "foo:bar")); + free(t); + assert_se(p == original + 10); + + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, ":", 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(streq(t, "foo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(streq(t, "foo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL); + assert_se(p == original + 5); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo\\ bar")); + free(t); + assert_se(p == original + 10); + + p = original = "\\w+@\\K[\\d.]+"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\\w+@\\K[\\d.]+"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "\\w+@\\K[\\d.]+")); + free(t); + assert_se(isempty(p)); + + p = original = "\\w+\\b"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "\\w+\b")); + free(t); + assert_se(isempty(p)); + + p = original = "-N ''"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "-N")); + free(t); + assert_se(p == original + 3); + + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "")); + free(t); + assert_se(isempty(p)); + + p = original = ":foo\\:bar::waldo:"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(t); + assert_se(streq(t, "")); + free(t); + assert_se(p == original + 1); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(streq(t, "foo:bar")); + free(t); + assert_se(p == original + 10); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(t); + assert_se(streq(t, "")); + free(t); + assert_se(p == original + 11); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(streq(t, "waldo")); + free(t); + assert_se(p == original + 17); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(streq(t, "")); + free(t); + assert_se(p == NULL); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 0); + assert_se(!t); + assert_se(!p); + + p = "foo\\xbar"; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "fooxbar")); + free(t); + assert_se(p == NULL); + + p = "foo\\xbar"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RETAIN_ESCAPE) > 0); + assert_se(streq(t, "foo\\xbar")); + free(t); + assert_se(p == NULL); +} + +static void test_extract_first_word_and_warn(void) { + const char *p, *original; + char *t; + + p = original = "foobar waldo"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(p == original + 7); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\"foobar\" \'waldo\'"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(p == original + 9); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\""; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\'"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\'fooo"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\'fooo"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = " foo\\ba\\x6ar "; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foo\ba\x6ar")); + free(t); + assert_se(isempty(p)); + + p = original = " foo\\ba\\x6ar "; + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foobax6ar")); + free(t); + assert_se(isempty(p)); + + p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "föo")); + free(t); + assert_se(p == original + 13); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "pi\360\237\222\251le")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foo")); + free(t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foo")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo\\ bar")); + free(t); + assert_se(p == original + 10); + + p = original = "\\w+@\\K[\\d.]+"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "\\w+@\\K[\\d.]+")); + free(t); + assert_se(isempty(p)); + + p = original = "\\w+\\b"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "\\w+\b")); + free(t); + assert_se(isempty(p)); +} + +static void test_extract_many_words(void) { + const char *p, *original; + char *a, *b, *c; + + p = original = "foobar waldi piep"; + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 3); + assert_se(isempty(p)); + assert_se(streq_ptr(a, "foobar")); + assert_se(streq_ptr(b, "waldi")); + assert_se(streq_ptr(c, "piep")); + free(a); + free(b); + free(c); + + p = original = "'foobar' wa\"ld\"i "; + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 2); + assert_se(isempty(p)); + assert_se(streq_ptr(a, "'foobar'")); + assert_se(streq_ptr(b, "wa\"ld\"i")); + assert_se(streq_ptr(c, NULL)); + free(a); + free(b); + + p = original = "'foobar' wa\"ld\"i "; + assert_se(extract_many_words(&p, NULL, EXTRACT_QUOTES, &a, &b, &c, NULL) == 2); + assert_se(isempty(p)); + assert_se(streq_ptr(a, "foobar")); + assert_se(streq_ptr(b, "waldi")); + assert_se(streq_ptr(c, NULL)); + free(a); + free(b); + + p = original = ""; + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0); + assert_se(isempty(p)); + assert_se(streq_ptr(a, NULL)); + assert_se(streq_ptr(b, NULL)); + assert_se(streq_ptr(c, NULL)); + + p = original = " "; + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0); + assert_se(isempty(p)); + assert_se(streq_ptr(a, NULL)); + assert_se(streq_ptr(b, NULL)); + assert_se(streq_ptr(c, NULL)); + + p = original = "foobar"; + assert_se(extract_many_words(&p, NULL, 0, NULL) == 0); + assert_se(p == original); + + p = original = "foobar waldi"; + assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1); + assert_se(p == original+7); + assert_se(streq_ptr(a, "foobar")); + free(a); + + p = original = " foobar "; + assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1); + assert_se(isempty(p)); + assert_se(streq_ptr(a, "foobar")); + free(a); +} + +int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); + + test_extract_first_word(); + test_extract_first_word_and_warn(); + test_extract_many_words(); + + return 0; +} diff --git a/src/test/test-fd-util.c b/src/test/test-fd-util.c new file mode 100644 index 0000000000..f555bb976c --- /dev/null +++ b/src/test/test-fd-util.c @@ -0,0 +1,103 @@ +/*** + This file is part of systemd. + + Copyright 2010 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> +#include <unistd.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "macro.h" + +static void test_close_many(void) { + int fds[3]; + char name0[] = "/tmp/test-close-many.XXXXXX"; + char name1[] = "/tmp/test-close-many.XXXXXX"; + char name2[] = "/tmp/test-close-many.XXXXXX"; + + fds[0] = mkostemp_safe(name0); + fds[1] = mkostemp_safe(name1); + fds[2] = mkostemp_safe(name2); + + close_many(fds, 2); + + assert_se(fcntl(fds[0], F_GETFD) == -1); + assert_se(fcntl(fds[1], F_GETFD) == -1); + assert_se(fcntl(fds[2], F_GETFD) >= 0); + + safe_close(fds[2]); + + unlink(name0); + unlink(name1); + unlink(name2); +} + +static void test_close_nointr(void) { + char name[] = "/tmp/test-test-close_nointr.XXXXXX"; + int fd; + + fd = mkostemp_safe(name); + assert_se(fd >= 0); + assert_se(close_nointr(fd) >= 0); + assert_se(close_nointr(fd) < 0); + + unlink(name); +} + +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); +} + +int main(int argc, char *argv[]) { + test_close_many(); + test_close_nointr(); + test_same_fd(); + + return 0; +} diff --git a/src/test/test-fdset.c b/src/test/test-fdset.c index 242c5d9dc2..adbf99a7ec 100644 --- a/src/test/test-fdset.c +++ b/src/test/test-fdset.c @@ -20,16 +20,18 @@ #include <fcntl.h> #include <unistd.h> +#include "fd-util.h" #include "fdset.h" -#include "util.h" +#include "fileio.h" #include "macro.h" +#include "util.h" static void test_fdset_new_fill(void) { int fd = -1; _cleanup_fdset_free_ FDSet *fdset = NULL; char name[] = "/tmp/test-fdset_new_fill.XXXXXX"; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); assert_se(fdset_new_fill(&fdset) >= 0); assert_se(fdset_contains(fdset, fd)); @@ -43,7 +45,7 @@ static void test_fdset_put_dup(void) { _cleanup_fdset_free_ FDSet *fdset = NULL; char name[] = "/tmp/test-fdset_put_dup.XXXXXX"; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); fdset = fdset_new(); @@ -62,7 +64,7 @@ static void test_fdset_cloexec(void) { int flags = -1; char name[] = "/tmp/test-fdset_cloexec.XXXXXX"; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); fdset = fdset_new(); @@ -89,7 +91,7 @@ static void test_fdset_close_others(void) { int flags = -1; char name[] = "/tmp/test-fdset_close_others.XXXXXX"; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); fdset = fdset_new(); @@ -111,7 +113,7 @@ static void test_fdset_remove(void) { FDSet *fdset = NULL; char name[] = "/tmp/test-fdset_remove.XXXXXX"; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); fdset = fdset_new(); @@ -134,7 +136,7 @@ static void test_fdset_iterate(void) { int c = 0; int a; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); fdset = fdset_new(); @@ -159,7 +161,7 @@ static void test_fdset_isempty(void) { _cleanup_fdset_free_ FDSet *fdset = NULL; char name[] = "/tmp/test-fdset_isempty.XXXXXX"; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); fdset = fdset_new(); @@ -177,7 +179,7 @@ static void test_fdset_steal_first(void) { _cleanup_fdset_free_ FDSet *fdset = NULL; char name[] = "/tmp/test-fdset_steal_first.XXXXXX"; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); fdset = fdset_new(); diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index be3a87958f..92663ef66f 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,17 +17,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <fcntl.h> +#include <stdio.h> #include <unistd.h> -#include "util.h" -#include "process-util.h" +#include "alloc-util.h" +#include "ctype.h" +#include "def.h" +#include "env-util.h" +#include "fd-util.h" #include "fileio.h" +#include "io-util.h" +#include "parse-util.h" +#include "process-util.h" +#include "string-util.h" #include "strv.h" -#include "env-util.h" -#include "def.h" -#include "ctype.h" +#include "util.h" static void test_parse_env_file(void) { char t[] = "/tmp/test-fileio-in-XXXXXX", @@ -42,11 +45,11 @@ static void test_parse_env_file(void) { char **i; unsigned k; - fd = mkostemp_safe(p, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(p); assert_se(fd >= 0); close(fd); - fd = mkostemp_safe(t, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(t); assert_se(fd >= 0); f = fdopen(fd, "w"); @@ -155,11 +158,11 @@ static void test_parse_multiline_env_file(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL; char **i; - fd = mkostemp_safe(p, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(p); assert_se(fd >= 0); close(fd); - fd = mkostemp_safe(t, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(t); assert_se(fd >= 0); f = fdopen(fd, "w"); @@ -208,7 +211,7 @@ static void test_executable_is_script(void) { FILE *f; char *command; - fd = mkostemp_safe(t, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(t); assert_se(fd >= 0); f = fdopen(fd, "w"); @@ -241,18 +244,18 @@ static void test_status_field(void) { unsigned long long total = 0, buffers = 0; int r; - assert_se(get_status_field("/proc/self/status", "\nThreads:", &t) == 0); + assert_se(get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t) == 0); puts(t); assert_se(streq(t, "1")); - r = get_status_field("/proc/meminfo", "MemTotal:", &p); + r = get_proc_field("/proc/meminfo", "MemTotal", WHITESPACE, &p); if (r != -ENOENT) { assert_se(r == 0); puts(p); assert_se(safe_atollu(p, &total) == 0); } - r = get_status_field("/proc/meminfo", "\nBuffers:", &s); + r = get_proc_field("/proc/meminfo", "Buffers", WHITESPACE, &s); if (r != -ENOENT) { assert_se(r == 0); puts(s); @@ -263,7 +266,7 @@ static void test_status_field(void) { assert_se(buffers < total); /* Seccomp should be a good test for field full of zeros. */ - r = get_status_field("/proc/meminfo", "\nSeccomp:", &z); + r = get_proc_field("/proc/meminfo", "Seccomp", WHITESPACE, &z); if (r != -ENOENT) { assert_se(r == 0); puts(z); @@ -286,7 +289,7 @@ static void test_capeff(void) { assert_se(r == 0); assert_se(*capeff); - p = capeff[strspn(capeff, DIGITS "abcdefABCDEF")]; + p = capeff[strspn(capeff, HEXDIGITS)]; assert_se(!p || isspace(p)); } } @@ -297,7 +300,7 @@ static void test_write_string_stream(void) { int fd; char buf[64]; - fd = mkostemp_safe(fn, O_RDWR); + fd = mkostemp_safe(fn); assert_se(fd >= 0); f = fdopen(fd, "r"); @@ -331,7 +334,7 @@ static void test_write_string_file(void) { char buf[64] = {}; _cleanup_close_ int fd; - fd = mkostemp_safe(fn, O_RDWR); + fd = mkostemp_safe(fn); assert_se(fd >= 0); assert_se(write_string_file(fn, "boohoo", WRITE_STRING_FILE_CREATE) == 0); @@ -347,7 +350,7 @@ static void test_write_string_file_no_create(void) { _cleanup_close_ int fd; char buf[64] = {0}; - fd = mkostemp_safe(fn, O_RDWR); + fd = mkostemp_safe(fn); assert_se(fd >= 0); assert_se(write_string_file("/a/file/which/does/not/exists/i/guess", "boohoo", 0) < 0); @@ -359,6 +362,26 @@ static void test_write_string_file_no_create(void) { unlink(fn); } +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); + assert_se((buf2 = strjoin(buf, "\n", NULL))); + + 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); +} + static void test_load_env_file_pairs(void) { char fn[] = "/tmp/test-load_env_file_pairs-XXXXXX"; int fd; @@ -367,7 +390,7 @@ static void test_load_env_file_pairs(void) { _cleanup_strv_free_ char **l = NULL; char **k, **v; - fd = mkostemp_safe(fn, O_RDWR); + fd = mkostemp_safe(fn); assert_se(fd >= 0); r = write_string_file(fn, @@ -403,6 +426,134 @@ static void test_load_env_file_pairs(void) { unlink(fn); } +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; + + fd = mkostemp_safe(name); + 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; + + fd = mkostemp_safe(name); + 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], ""); + + fd = mkostemp_safe(name); + 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); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -415,7 +566,12 @@ int main(int argc, char *argv[]) { test_write_string_stream(); test_write_string_file(); test_write_string_file_no_create(); + test_write_string_file_verify(); test_load_env_file_pairs(); + test_search_and_fopen(); + test_search_and_fopen_nulstr(); + test_writing_tmpfile(); + test_tempfn(); return 0; } diff --git a/src/test/test-firewall-util.c b/src/test/test-firewall-util.c index d636e427c4..77e809c5bf 100644 --- a/src/test/test-firewall-util.c +++ b/src/test/test-firewall-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,8 +17,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "log.h" #include "firewall-util.h" +#include "log.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))} diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c new file mode 100644 index 0000000000..53a3cdc663 --- /dev/null +++ b/src/test/test-fs-util.c @@ -0,0 +1,243 @@ +/*** + This file is part of systemd. + + Copyright 2010 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 <unistd.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "macro.h" +#include "mkdir.h" +#include "path-util.h" +#include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" + +static void test_chase_symlinks(void) { + _cleanup_free_ char *result = NULL; + char temp[] = "/tmp/test-chase.XXXXXX"; + const char *top, *p, *q; + int r; + + assert_se(mkdtemp(temp)); + + top = strjoina(temp, "/top"); + assert_se(mkdir(top, 0700) >= 0); + + p = strjoina(top, "/dot"); + assert_se(symlink(".", p) >= 0); + + p = strjoina(top, "/dotdot"); + assert_se(symlink("..", p) >= 0); + + p = strjoina(top, "/dotdota"); + assert_se(symlink("../a", p) >= 0); + + p = strjoina(temp, "/a"); + assert_se(symlink("b", p) >= 0); + + p = strjoina(temp, "/b"); + assert_se(symlink("/usr", p) >= 0); + + p = strjoina(temp, "/start"); + assert_se(symlink("top/dot/dotdota", p) >= 0); + + r = chase_symlinks(p, NULL, &result); + assert_se(r >= 0); + assert_se(path_equal(result, "/usr")); + + result = mfree(result); + r = chase_symlinks(p, temp, &result); + assert_se(r == -ENOENT); + + q = strjoina(temp, "/usr"); + assert_se(mkdir(q, 0700) >= 0); + + r = chase_symlinks(p, temp, &result); + assert_se(r >= 0); + assert_se(path_equal(result, q)); + + p = strjoina(temp, "/slash"); + assert_se(symlink("/", p) >= 0); + + result = mfree(result); + r = chase_symlinks(p, NULL, &result); + assert_se(r >= 0); + assert_se(path_equal(result, "/")); + + result = mfree(result); + r = chase_symlinks(p, temp, &result); + assert_se(r >= 0); + assert_se(path_equal(result, temp)); + + p = strjoina(temp, "/slashslash"); + assert_se(symlink("///usr///", p) >= 0); + + result = mfree(result); + r = chase_symlinks(p, NULL, &result); + assert_se(r >= 0); + assert_se(path_equal(result, "/usr")); + + result = mfree(result); + r = chase_symlinks(p, temp, &result); + assert_se(r >= 0); + assert_se(path_equal(result, q)); + + result = mfree(result); + r = chase_symlinks("/etc/./.././", NULL, &result); + assert_se(r >= 0); + assert_se(path_equal(result, "/")); + + result = mfree(result); + r = chase_symlinks("/etc/./.././", "/etc", &result); + assert_se(r == -EINVAL); + + result = mfree(result); + r = chase_symlinks("/etc/machine-id/foo", NULL, &result); + assert_se(r == -ENOTDIR); + + result = mfree(result); + p = strjoina(temp, "/recursive-symlink"); + assert_se(symlink("recursive-symlink", p) >= 0); + r = chase_symlinks(p, NULL, &result); + assert_se(r == -ELOOP); + + assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); +} + +static void test_unlink_noerrno(void) { + char name[] = "/tmp/test-close_nointr.XXXXXX"; + int fd; + + fd = mkostemp_safe(name); + assert_se(fd >= 0); + assert_se(close_nointr(fd) >= 0); + + { + PROTECT_ERRNO; + errno = -42; + assert_se(unlink_noerrno(name) >= 0); + assert_se(errno == -42); + assert_se(unlink_noerrno(name) < 0); + assert_se(errno == -42); + } +} + +static void test_readlink_and_make_absolute(void) { + char tempdir[] = "/tmp/test-readlink_and_make_absolute"; + char name[] = "/tmp/test-readlink_and_make_absolute/original"; + char name2[] = "test-readlink_and_make_absolute/original"; + char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias"; + char *r = NULL; + + assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid()) >= 0); + assert_se(touch(name) >= 0); + + assert_se(symlink(name, name_alias) >= 0); + assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); + assert_se(streq(r, name)); + free(r); + assert_se(unlink(name_alias) >= 0); + + assert_se(chdir(tempdir) >= 0); + assert_se(symlink(name2, name_alias) >= 0); + assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); + assert_se(streq(r, name)); + free(r); + assert_se(unlink(name_alias) >= 0); + + assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); +} + +static void test_get_files_in_directory(void) { + _cleanup_strv_free_ char **l = NULL, **t = NULL; + + assert_se(get_files_in_directory("/tmp", &l) >= 0); + assert_se(get_files_in_directory(".", &t) >= 0); + assert_se(get_files_in_directory(".", NULL) >= 0); +} + +static void test_var_tmp(void) { + _cleanup_free_ char *tmpdir_backup = NULL, *temp_backup = NULL, *tmp_backup = NULL; + const char *tmp_dir = NULL, *t; + + t = getenv("TMPDIR"); + if (t) { + tmpdir_backup = strdup(t); + assert_se(tmpdir_backup); + } + + t = getenv("TEMP"); + if (t) { + temp_backup = strdup(t); + assert_se(temp_backup); + } + + t = getenv("TMP"); + if (t) { + tmp_backup = strdup(t); + assert_se(tmp_backup); + } + + assert(unsetenv("TMPDIR") >= 0); + assert(unsetenv("TEMP") >= 0); + assert(unsetenv("TMP") >= 0); + + assert_se(var_tmp_dir(&tmp_dir) >= 0); + assert_se(streq(tmp_dir, "/var/tmp")); + + assert_se(setenv("TMPDIR", "/tmp", true) >= 0); + assert_se(streq(getenv("TMPDIR"), "/tmp")); + + assert_se(var_tmp_dir(&tmp_dir) >= 0); + assert_se(streq(tmp_dir, "/tmp")); + + assert_se(setenv("TMPDIR", "/88_does_not_exist_88", true) >= 0); + assert_se(streq(getenv("TMPDIR"), "/88_does_not_exist_88")); + + assert_se(var_tmp_dir(&tmp_dir) >= 0); + assert_se(streq(tmp_dir, "/var/tmp")); + + if (tmpdir_backup) { + assert_se(setenv("TMPDIR", tmpdir_backup, true) >= 0); + assert_se(streq(getenv("TMPDIR"), tmpdir_backup)); + } + + if (temp_backup) { + assert_se(setenv("TEMP", temp_backup, true) >= 0); + assert_se(streq(getenv("TEMP"), temp_backup)); + } + + if (tmp_backup) { + assert_se(setenv("TMP", tmp_backup, true) >= 0); + assert_se(streq(getenv("TMP"), tmp_backup)); + } +} + +int main(int argc, char *argv[]) { + test_unlink_noerrno(); + test_readlink_and_make_absolute(); + test_get_files_in_directory(); + test_var_tmp(); + test_chase_symlinks(); + + return 0; +} diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c index 50e5dee0a7..63a4b8c243 100644 --- a/src/test/test-fstab-util.c +++ b/src/test/test-fstab-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,9 +17,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "fstab-util.h" -#include "util.h" #include "log.h" +#include "string-util.h" +#include "util.h" /* int fstab_filter_options(const char *opts, const char *names, @@ -131,8 +131,45 @@ static void test_fstab_yes_no_option(void) { assert_se(fstab_test_yes_no_option("nofail,nofail=0,fail=0", "nofail\0fail\0") == false); } +static void test_fstab_node_to_udev_node(void) { + char *n; + + n = fstab_node_to_udev_node("LABEL=applé/jack"); + puts(n); + assert_se(streq(n, "/dev/disk/by-label/applé\\x2fjack")); + free(n); + + n = fstab_node_to_udev_node("PARTLABEL=pinkié pie"); + puts(n); + assert_se(streq(n, "/dev/disk/by-partlabel/pinkié\\x20pie")); + free(n); + + n = fstab_node_to_udev_node("UUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); + puts(n); + assert_se(streq(n, "/dev/disk/by-uuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); + free(n); + + n = fstab_node_to_udev_node("PARTUUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); + puts(n); + assert_se(streq(n, "/dev/disk/by-partuuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); + free(n); + + n = fstab_node_to_udev_node("PONIES=awesome"); + puts(n); + assert_se(streq(n, "PONIES=awesome")); + free(n); + + n = fstab_node_to_udev_node("/dev/xda1"); + puts(n); + assert_se(streq(n, "/dev/xda1")); + free(n); +} + int main(void) { test_fstab_filter_options(); test_fstab_find_pri(); test_fstab_yes_no_option(); + test_fstab_node_to_udev_node(); + + return 0; } diff --git a/src/test/test-glob-util.c b/src/test/test-glob-util.c new file mode 100644 index 0000000000..9eea3eb608 --- /dev/null +++ b/src/test/test-glob-util.c @@ -0,0 +1,50 @@ +/*** + This file is part of systemd. + + Copyright 2010 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> +#include <unistd.h> + +#include "alloc-util.h" +#include "fileio.h" +#include "glob-util.h" +#include "macro.h" + +static void test_glob_exists(void) { + char name[] = "/tmp/test-glob_exists.XXXXXX"; + int fd = -1; + int r; + + fd = mkostemp_safe(name); + assert_se(fd >= 0); + close(fd); + + r = glob_exists("/tmp/test-glob_exists*"); + assert_se(r == 1); + + r = unlink(name); + assert_se(r == 0); + r = glob_exists("/tmp/test-glob_exists*"); + assert_se(r == 0); +} + +int main(void) { + test_glob_exists(); + + return 0; +} diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c index 057b6c1dc1..1bd5c02f87 100644 --- a/src/test/test-hashmap-plain.c +++ b/src/test/test-hashmap-plain.c @@ -17,9 +17,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" +#include "hashmap.h" +#include "string-util.h" #include "strv.h" #include "util.h" -#include "hashmap.h" void test_hashmap_funcs(void); @@ -321,26 +323,29 @@ static void test_hashmap_remove_value(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; char *r; - r = hashmap_remove_value(NULL, "key 1", (void*) "val 1"); + char val1[] = "val 1"; + char val2[] = "val 2"; + + r = hashmap_remove_value(NULL, "key 1", val1); assert_se(r == NULL); m = hashmap_new(&string_hash_ops); assert_se(m); - r = hashmap_remove_value(m, "key 1", (void*) "val 1"); + r = hashmap_remove_value(m, "key 1", val1); assert_se(r == NULL); - hashmap_put(m, "key 1", (void*) "val 1"); - hashmap_put(m, "key 2", (void*) "val 2"); + hashmap_put(m, "key 1", val1); + hashmap_put(m, "key 2", val2); - r = hashmap_remove_value(m, "key 1", (void*) "val 1"); + r = hashmap_remove_value(m, "key 1", val1); assert_se(streq(r, "val 1")); r = hashmap_get(m, "key 2"); assert_se(streq(r, "val 2")); assert_se(!hashmap_get(m, "key 1")); - r = hashmap_remove_value(m, "key 2", (void*) "val 1"); + r = hashmap_remove_value(m, "key 2", val1); assert_se(r == NULL); r = hashmap_get(m, "key 2"); @@ -692,8 +697,8 @@ static void test_hashmap_get2(void) { hashmap_free_free_free(m); } -static unsigned long crippled_hashmap_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - return trivial_hash_func(p, hash_key) & 0xff; +static void crippled_hashmap_func(const void *p, struct siphash *state) { + return trivial_hash_func(INT_TO_PTR(PTR_TO_INT(p) & 0xff), state); } static const struct hash_ops crippled_hashmap_ops = { @@ -710,7 +715,7 @@ static void test_hashmap_many(void) { unsigned n_entries; } tests[] = { { .ops = NULL, .n_entries = 1 << 20 }, - { .ops = &crippled_hashmap_ops, .n_entries = 1 << 11 }, + { .ops = &crippled_hashmap_ops, .n_entries = 1 << 14 }, }; diff --git a/src/test/test-hashmap.c b/src/test/test-hashmap.c index d0e65001f5..83cea360e6 100644 --- a/src/test/test-hashmap.c +++ b/src/test/test-hashmap.c @@ -17,8 +17,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "hashmap.h" +#include "util.h" void test_hashmap_funcs(void); void test_ordered_hashmap_funcs(void); diff --git a/src/test/test-helper.h b/src/test/test-helper.h index f75dd3374a..ddb10f88fd 100644 --- a/src/test/test-helper.h +++ b/src/test/test-helper.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,9 +21,21 @@ #include "sd-daemon.h" +#include "macro.h" + #define TEST_REQ_RUNNING_SYSTEMD(x) \ if (sd_booted() > 0) { \ x; \ } else { \ printf("systemd not booted skipping '%s'\n", #x); \ } + +#define MANAGER_SKIP_TEST(r) \ + IN_SET(r, \ + -EPERM, \ + -EACCES, \ + -EADDRINUSE, \ + -EHOSTDOWN, \ + -ENOENT, \ + -ENOMEDIUM /* cannot determine cgroup */ \ + ) diff --git a/src/test/test-hexdecoct.c b/src/test/test-hexdecoct.c new file mode 100644 index 0000000000..276f25d091 --- /dev/null +++ b/src/test/test-hexdecoct.c @@ -0,0 +1,387 @@ +/*** + This file is part of systemd. + + Copyright 2010 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 "alloc-util.h" +#include "hexdecoct.h" +#include "macro.h" +#include "string-util.h" + +static void test_hexchar(void) { + assert_se(hexchar(0xa) == 'a'); + assert_se(hexchar(0x0) == '0'); +} + +static void test_unhexchar(void) { + assert_se(unhexchar('a') == 0xA); + assert_se(unhexchar('A') == 0xA); + assert_se(unhexchar('0') == 0x0); +} + +static void test_base32hexchar(void) { + assert_se(base32hexchar(0) == '0'); + assert_se(base32hexchar(9) == '9'); + assert_se(base32hexchar(10) == 'A'); + assert_se(base32hexchar(31) == 'V'); +} + +static void test_unbase32hexchar(void) { + assert_se(unbase32hexchar('0') == 0); + assert_se(unbase32hexchar('9') == 9); + assert_se(unbase32hexchar('A') == 10); + assert_se(unbase32hexchar('V') == 31); + assert_se(unbase32hexchar('=') == -EINVAL); +} + +static void test_base64char(void) { + assert_se(base64char(0) == 'A'); + assert_se(base64char(26) == 'a'); + assert_se(base64char(63) == '/'); +} + +static void test_unbase64char(void) { + assert_se(unbase64char('A') == 0); + assert_se(unbase64char('Z') == 25); + assert_se(unbase64char('a') == 26); + assert_se(unbase64char('z') == 51); + assert_se(unbase64char('0') == 52); + assert_se(unbase64char('9') == 61); + assert_se(unbase64char('+') == 62); + assert_se(unbase64char('/') == 63); + assert_se(unbase64char('=') == -EINVAL); +} + +static void test_octchar(void) { + assert_se(octchar(00) == '0'); + assert_se(octchar(07) == '7'); +} + +static void test_unoctchar(void) { + assert_se(unoctchar('0') == 00); + assert_se(unoctchar('7') == 07); +} + +static void test_decchar(void) { + assert_se(decchar(0) == '0'); + assert_se(decchar(9) == '9'); +} + +static void test_undecchar(void) { + assert_se(undecchar('0') == 0); + assert_se(undecchar('9') == 9); +} + +static void test_unhexmem(void) { + const char *hex = "efa214921"; + const char *hex_invalid = "efa214921o"; + _cleanup_free_ char *hex2 = NULL; + _cleanup_free_ void *mem = NULL; + size_t len; + + assert_se(unhexmem(hex, strlen(hex), &mem, &len) == 0); + assert_se(unhexmem(hex, strlen(hex) + 1, &mem, &len) == -EINVAL); + assert_se(unhexmem(hex_invalid, strlen(hex_invalid), &mem, &len) == -EINVAL); + + assert_se((hex2 = hexmem(mem, len))); + + free(mem); + + assert_se(memcmp(hex, hex2, strlen(hex)) == 0); + + free(hex2); + + assert_se(unhexmem(hex, strlen(hex) - 1, &mem, &len) == 0); + assert_se((hex2 = hexmem(mem, len))); + assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0); +} + +/* https://tools.ietf.org/html/rfc4648#section-10 */ +static void test_base32hexmem(void) { + char *b32; + + b32 = base32hexmem("", strlen(""), true); + assert_se(b32); + assert_se(streq(b32, "")); + free(b32); + + b32 = base32hexmem("f", strlen("f"), true); + assert_se(b32); + assert_se(streq(b32, "CO======")); + free(b32); + + b32 = base32hexmem("fo", strlen("fo"), true); + assert_se(b32); + assert_se(streq(b32, "CPNG====")); + free(b32); + + b32 = base32hexmem("foo", strlen("foo"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMU===")); + free(b32); + + b32 = base32hexmem("foob", strlen("foob"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMUOG=")); + free(b32); + + b32 = base32hexmem("fooba", strlen("fooba"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1")); + free(b32); + + b32 = base32hexmem("foobar", strlen("foobar"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1E8======")); + free(b32); + + b32 = base32hexmem("", strlen(""), false); + assert_se(b32); + assert_se(streq(b32, "")); + free(b32); + + b32 = base32hexmem("f", strlen("f"), false); + assert_se(b32); + assert_se(streq(b32, "CO")); + free(b32); + + b32 = base32hexmem("fo", strlen("fo"), false); + assert_se(b32); + assert_se(streq(b32, "CPNG")); + free(b32); + + b32 = base32hexmem("foo", strlen("foo"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMU")); + free(b32); + + b32 = base32hexmem("foob", strlen("foob"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMUOG")); + free(b32); + + b32 = base32hexmem("fooba", strlen("fooba"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1")); + free(b32); + + b32 = base32hexmem("foobar", strlen("foobar"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1E8")); + free(b32); +} + +static void test_unbase32hexmem(void) { + void *mem; + size_t len; + + assert_se(unbase32hexmem("", strlen(""), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "")); + free(mem); + + assert_se(unbase32hexmem("CO======", strlen("CO======"), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "f")); + free(mem); + + assert_se(unbase32hexmem("CPNG====", strlen("CPNG===="), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fo")); + free(mem); + + assert_se(unbase32hexmem("CPNMU===", strlen("CPNMU==="), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foo")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foob")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fooba")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foobar")); + free(mem); + + assert_se(unbase32hexmem("A", strlen("A"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("A=======", strlen("A======="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAA=====", strlen("AAA====="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAA==", strlen("AAAAAA=="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AB======", strlen("AB======"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAB====", strlen("AAAB===="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAB===", strlen("AAAAB==="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAAB=", strlen("AAAAAAB="), true, &mem, &len) == -EINVAL); + + assert_se(unbase32hexmem("XPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CXNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPXMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNXUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMXOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUXJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUOX1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUOJX", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + + assert_se(unbase32hexmem("", strlen(""), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "")); + free(mem); + + assert_se(unbase32hexmem("CO", strlen("CO"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "f")); + free(mem); + + assert_se(unbase32hexmem("CPNG", strlen("CPNG"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fo")); + free(mem); + + assert_se(unbase32hexmem("CPNMU", strlen("CPNMU"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foo")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOG", strlen("CPNMUOG"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foob")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fooba")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1E8", strlen("CPNMUOJ1E8"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foobar")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAA", strlen("AAA"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAA", strlen("AAAAAA"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AB", strlen("AB"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAB", strlen("AAAB"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAB", strlen("AAAAB"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAAB", strlen("AAAAAAB"), false, &mem, &len) == -EINVAL); +} + +/* https://tools.ietf.org/html/rfc4648#section-10 */ +static void test_base64mem(void) { + char *b64; + + assert_se(base64mem("", strlen(""), &b64) == 0); + assert_se(streq(b64, "")); + free(b64); + + assert_se(base64mem("f", strlen("f"), &b64) == 4); + assert_se(streq(b64, "Zg==")); + free(b64); + + assert_se(base64mem("fo", strlen("fo"), &b64) == 4); + assert_se(streq(b64, "Zm8=")); + free(b64); + + assert_se(base64mem("foo", strlen("foo"), &b64) == 4); + assert_se(streq(b64, "Zm9v")); + free(b64); + + assert_se(base64mem("foob", strlen("foob"), &b64) == 8); + assert_se(streq(b64, "Zm9vYg==")); + free(b64); + + assert_se(base64mem("fooba", strlen("fooba"), &b64) == 8); + assert_se(streq(b64, "Zm9vYmE=")); + free(b64); + + assert_se(base64mem("foobar", strlen("foobar"), &b64) == 8); + assert_se(streq(b64, "Zm9vYmFy")); + free(b64); +} + +static void test_unbase64mem(void) { + void *mem; + size_t len; + + assert_se(unbase64mem("", strlen(""), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "")); + free(mem); + + assert_se(unbase64mem("Zg==", strlen("Zg=="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "f")); + free(mem); + + assert_se(unbase64mem("Zm8=", strlen("Zm8="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fo")); + free(mem); + + assert_se(unbase64mem("Zm9v", strlen("Zm9v"), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foo")); + free(mem); + + assert_se(unbase64mem("Zm9vYg==", strlen("Zm9vYg=="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foob")); + free(mem); + + assert_se(unbase64mem("Zm9vYmE=", strlen("Zm9vYmE="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fooba")); + free(mem); + + assert_se(unbase64mem("Zm9vYmFy", strlen("Zm9vYmFy"), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foobar")); + free(mem); + + assert_se(unbase64mem("A", strlen("A"), &mem, &len) == -EINVAL); + assert_se(unbase64mem("A====", strlen("A===="), &mem, &len) == -EINVAL); + assert_se(unbase64mem("AAB==", strlen("AAB=="), &mem, &len) == -EINVAL); + assert_se(unbase64mem("AAAB=", strlen("AAAB="), &mem, &len) == -EINVAL); +} + +static void test_hexdump(void) { + uint8_t data[146]; + unsigned i; + + hexdump(stdout, NULL, 0); + hexdump(stdout, "", 0); + hexdump(stdout, "", 1); + hexdump(stdout, "x", 1); + hexdump(stdout, "x", 2); + hexdump(stdout, "foobar", 7); + hexdump(stdout, "f\nobar", 7); + hexdump(stdout, "xxxxxxxxxxxxxxxxxxxxyz", 23); + + for (i = 0; i < ELEMENTSOF(data); i++) + data[i] = i*2; + + hexdump(stdout, data, sizeof(data)); +} + +int main(int argc, char *argv[]) { + test_hexchar(); + test_unhexchar(); + test_base32hexchar(); + test_unbase32hexchar(); + test_base64char(); + test_unbase64char(); + test_octchar(); + test_unoctchar(); + test_decchar(); + test_undecchar(); + test_unhexmem(); + test_base32hexmem(); + test_unbase32hexmem(); + test_base64mem(); + test_unbase64mem(); + test_hexdump(); + + return 0; +} diff --git a/src/test/test-hostname-util.c b/src/test/test-hostname-util.c new file mode 100644 index 0000000000..d2c3ea5e0d --- /dev/null +++ b/src/test/test-hostname-util.c @@ -0,0 +1,160 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2013 Thomas H.P. Andersen + 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 "alloc-util.h" +#include "fileio.h" +#include "hostname-util.h" +#include "string-util.h" +#include "util.h" + +static void test_hostname_is_valid(void) { + assert_se(hostname_is_valid("foobar", false)); + assert_se(hostname_is_valid("foobar.com", false)); + assert_se(!hostname_is_valid("foobar.com.", false)); + assert_se(hostname_is_valid("fooBAR", false)); + assert_se(hostname_is_valid("fooBAR.com", false)); + assert_se(!hostname_is_valid("fooBAR.", false)); + assert_se(!hostname_is_valid("fooBAR.com.", false)); + assert_se(!hostname_is_valid("fööbar", false)); + assert_se(!hostname_is_valid("", false)); + assert_se(!hostname_is_valid(".", false)); + assert_se(!hostname_is_valid("..", false)); + assert_se(!hostname_is_valid("foobar.", false)); + assert_se(!hostname_is_valid(".foobar", false)); + assert_se(!hostname_is_valid("foo..bar", false)); + assert_se(!hostname_is_valid("foo.bar..", false)); + assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", false)); + assert_se(!hostname_is_valid("au-xph5-rvgrdsb5hcxc-47et3a5vvkrc-server-wyoz4elpdpe3.openstack.local", false)); + + assert_se(hostname_is_valid("foobar", true)); + assert_se(hostname_is_valid("foobar.com", true)); + assert_se(hostname_is_valid("foobar.com.", true)); + assert_se(hostname_is_valid("fooBAR", true)); + assert_se(hostname_is_valid("fooBAR.com", true)); + assert_se(!hostname_is_valid("fooBAR.", true)); + assert_se(hostname_is_valid("fooBAR.com.", true)); + assert_se(!hostname_is_valid("fööbar", true)); + assert_se(!hostname_is_valid("", true)); + assert_se(!hostname_is_valid(".", true)); + assert_se(!hostname_is_valid("..", true)); + assert_se(!hostname_is_valid("foobar.", true)); + assert_se(!hostname_is_valid(".foobar", true)); + assert_se(!hostname_is_valid("foo..bar", true)); + assert_se(!hostname_is_valid("foo.bar..", true)); + assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", true)); +} + +static void test_hostname_cleanup(void) { + char *s; + + s = strdupa("foobar"); + assert_se(streq(hostname_cleanup(s), "foobar")); + s = strdupa("foobar.com"); + assert_se(streq(hostname_cleanup(s), "foobar.com")); + s = strdupa("foobar.com."); + assert_se(streq(hostname_cleanup(s), "foobar.com")); + s = strdupa("fooBAR"); + assert_se(streq(hostname_cleanup(s), "fooBAR")); + s = strdupa("fooBAR.com"); + assert_se(streq(hostname_cleanup(s), "fooBAR.com")); + s = strdupa("fooBAR."); + assert_se(streq(hostname_cleanup(s), "fooBAR")); + s = strdupa("fooBAR.com."); + assert_se(streq(hostname_cleanup(s), "fooBAR.com")); + s = strdupa("fööbar"); + assert_se(streq(hostname_cleanup(s), "fbar")); + s = strdupa(""); + assert_se(isempty(hostname_cleanup(s))); + s = strdupa("."); + assert_se(isempty(hostname_cleanup(s))); + s = strdupa(".."); + assert_se(isempty(hostname_cleanup(s))); + s = strdupa("foobar."); + assert_se(streq(hostname_cleanup(s), "foobar")); + s = strdupa(".foobar"); + assert_se(streq(hostname_cleanup(s), "foobar")); + s = strdupa("foo..bar"); + assert_se(streq(hostname_cleanup(s), "foo.bar")); + s = strdupa("foo.bar.."); + assert_se(streq(hostname_cleanup(s), "foo.bar")); + s = strdupa("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); + assert_se(streq(hostname_cleanup(s), "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); +} + +static void test_read_hostname_config(void) { + char path[] = "/tmp/hostname.XXXXXX"; + char *hostname; + int fd; + + fd = mkostemp_safe(path); + assert(fd > 0); + close(fd); + + /* simple hostname */ + write_string_file(path, "foo", WRITE_STRING_FILE_CREATE); + assert_se(read_hostname_config(path, &hostname) == 0); + assert_se(streq(hostname, "foo")); + hostname = mfree(hostname); + + /* with comment */ + write_string_file(path, "# comment\nfoo", WRITE_STRING_FILE_CREATE); + assert_se(read_hostname_config(path, &hostname) == 0); + assert_se(hostname); + assert_se(streq(hostname, "foo")); + hostname = mfree(hostname); + + /* with comment and extra whitespace */ + write_string_file(path, "# comment\n\n foo ", WRITE_STRING_FILE_CREATE); + assert_se(read_hostname_config(path, &hostname) == 0); + assert_se(hostname); + assert_se(streq(hostname, "foo")); + hostname = mfree(hostname); + + /* cleans up name */ + write_string_file(path, "!foo/bar.com", WRITE_STRING_FILE_CREATE); + assert_se(read_hostname_config(path, &hostname) == 0); + assert_se(hostname); + assert_se(streq(hostname, "foobar.com")); + hostname = mfree(hostname); + + /* no value set */ + hostname = (char*) 0x1234; + write_string_file(path, "# nothing here\n", WRITE_STRING_FILE_CREATE); + assert_se(read_hostname_config(path, &hostname) == -ENOENT); + assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */ + + /* nonexisting file */ + assert_se(read_hostname_config("/non/existing", &hostname) == -ENOENT); + assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */ + + unlink(path); +} + +int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); + + test_hostname_is_valid(); + test_hostname_cleanup(); + test_read_hostname_config(); + + return 0; +} diff --git a/src/test/test-hostname.c b/src/test/test-hostname.c index dd50c5148c..b38507df5d 100644 --- a/src/test/test-hostname.c +++ b/src/test/test-hostname.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-id128.c b/src/test/test-id128.c index a6a0cd77a1..1c8e5549da 100644 --- a/src/test/test-id128.c +++ b/src/test/test-id128.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,11 +19,16 @@ #include <string.h> -#include "systemd/sd-id128.h" +#include "sd-daemon.h" +#include "sd-id128.h" -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "id128-util.h" #include "macro.h" -#include "sd-daemon.h" +#include "string-util.h" +#include "util.h" #define ID128_WALDI SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10) #define STR_WALDI "0102030405060708090a0b0c0d0e0f10" @@ -33,8 +36,9 @@ int main(int argc, char *argv[]) { sd_id128_t id, id2; - char t[33]; + char t[33], q[37]; _cleanup_free_ char *b = NULL; + _cleanup_close_ int fd = -1; assert_se(sd_id128_randomize(&id) == 0); printf("random: %s\n", sd_id128_to_string(id, t)); @@ -57,6 +61,17 @@ int main(int argc, char *argv[]) { printf("waldi2: %s\n", b); assert_se(streq(t, b)); + printf("waldi3: %s\n", id128_to_uuid_string(ID128_WALDI, q)); + assert_se(streq(q, UUID_WALDI)); + + b = mfree(b); + assert_se(asprintf(&b, ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(ID128_WALDI)) == 36); + printf("waldi4: %s\n", b); + assert_se(streq(q, b)); + + assert_se(sd_id128_from_string(STR_WALDI, &id) >= 0); + assert_se(sd_id128_equal(id, ID128_WALDI)); + assert_se(sd_id128_from_string(UUID_WALDI, &id) >= 0); assert_se(sd_id128_equal(id, ID128_WALDI)); @@ -74,5 +89,69 @@ int main(int argc, char *argv[]) { assert_se(!id128_is_valid("01020304-0506-0708-090a0b0c0d0e0f10")); assert_se(!id128_is_valid("010203040506-0708-090a-0b0c0d0e0f10")); + fd = open_tmpfile_unlinkable(NULL, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + + /* First, write as UUID */ + assert_se(sd_id128_randomize(&id) >= 0); + assert_se(id128_write_fd(fd, ID128_UUID, id, false) >= 0); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) == -EINVAL); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_UUID, &id2) >= 0); + assert_se(sd_id128_equal(id, id2)); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_ANY, &id2) >= 0); + assert_se(sd_id128_equal(id, id2)); + + /* Second, write as plain */ + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(ftruncate(fd, 0) >= 0); + + assert_se(sd_id128_randomize(&id) >= 0); + assert_se(id128_write_fd(fd, ID128_PLAIN, id, false) >= 0); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_UUID, &id2) == -EINVAL); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) >= 0); + assert_se(sd_id128_equal(id, id2)); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_ANY, &id2) >= 0); + assert_se(sd_id128_equal(id, id2)); + + /* Third, write plain without trailing newline */ + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(ftruncate(fd, 0) >= 0); + + assert_se(sd_id128_randomize(&id) >= 0); + assert_se(write(fd, sd_id128_to_string(id, t), 32) == 32); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_UUID, &id2) == -EINVAL); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) >= 0); + assert_se(sd_id128_equal(id, id2)); + + /* Third, write UUID without trailing newline */ + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(ftruncate(fd, 0) >= 0); + + assert_se(sd_id128_randomize(&id) >= 0); + assert_se(write(fd, id128_to_uuid_string(id, q), 36) == 36); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) == -EINVAL); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(id128_read_fd(fd, ID128_UUID, &id2) >= 0); + assert_se(sd_id128_equal(id, id2)); + return 0; } diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c new file mode 100644 index 0000000000..db1c928660 --- /dev/null +++ b/src/test/test-install-root.c @@ -0,0 +1,770 @@ +/*** + This file is part of systemd. + + Copyright 2011 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 "alloc-util.h" +#include "fileio.h" +#include "install.h" +#include "mkdir.h" +#include "rm-rf.h" +#include "string-util.h" + +static void test_basic_mask_and_enable(const char *root) { + const char *p; + UnitFileState state; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + + log_set_max_level(LOG_DEBUG); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/a.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) >= 0); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system/b.service"); + assert_se(symlink("a.service", p) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) >= 0); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system/c.service"); + assert_se(symlink("/usr/lib/systemd/system/a.service", p) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) >= 0); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system/d.service"); + assert_se(symlink("c.service", p) >= 0); + + /* This one is interesting, as d follows a relative, then an absolute symlink */ + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_mask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/dev/null")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service"); + assert_se(streq(changes[0].path, p)); + + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_MASKED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_MASKED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_MASKED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED); + + /* Enabling a masked unit should fail! */ + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ERFKILL); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + + /* Enabling it again should succeed but be a NOP */ + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + /* Disabling a disabled unit must suceed but be a NOP */ + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + /* Let's enable this indirectly via a symlink */ + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("d.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + + /* Let's try to reenable */ + + assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("b.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); + assert_se(streq(changes[0].path, p)); + assert_se(changes[1].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[1].source, "/usr/lib/systemd/system/a.service")); + assert_se(streq(changes[1].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +} + +static void test_linked_units(const char *root) { + const char *p, *q; + UnitFileState state; + UnitFileChange *changes = NULL; + unsigned n_changes = 0, i; + + /* + * We'll test three cases here: + * + * a) a unit file in /opt, that we use "systemctl link" and + * "systemctl enable" on to make it available to the system + * + * b) a unit file in /opt, that is statically linked into + * /usr/lib/systemd/system, that "enable" should work on + * correctly. + * + * c) a unit file in /opt, that is linked into + * /etc/systemd/system, and where "enable" should result in + * -ELOOP, since using information from /etc to generate + * information in /etc should not be allowed. + */ + + p = strjoina(root, "/opt/linked.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/opt/linked2.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/opt/linked3.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", NULL) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/linked2.service"); + assert_se(symlink("/opt/linked2.service", p) >= 0); + + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked3.service"); + assert_se(symlink("/opt/linked3.service", p) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED); + + /* First, let's link the unit into the search path */ + assert_se(unit_file_link(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/opt/linked.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED); + + /* Let's unlink it from the search path again */ + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); + + /* Now, let's not just link it, but also enable it */ + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service"); + q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); + for (i = 0 ; i < n_changes; i++) { + assert_se(changes[i].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[i].source, "/opt/linked.service")); + + if (p && streq(changes[i].path, p)) + p = NULL; + else if (q && streq(changes[i].path, q)) + q = NULL; + else + assert_not_reached("wut?"); + } + assert(!p && !q); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + + /* And let's unlink it again */ + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service"); + q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); + for (i = 0; i < n_changes; i++) { + assert_se(changes[i].type == UNIT_FILE_UNLINK); + + if (p && streq(changes[i].path, p)) + p = NULL; + else if (q && streq(changes[i].path, q)) + q = NULL; + else + assert_not_reached("wut?"); + } + assert(!p && !q); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked2.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked2.service"); + q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked2.service"); + for (i = 0 ; i < n_changes; i++) { + assert_se(changes[i].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[i].source, "/opt/linked2.service")); + + if (p && streq(changes[i].path, p)) + p = NULL; + else if (q && streq(changes[i].path, q)) + q = NULL; + else + assert_not_reached("wut?"); + } + assert(!p && !q); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked3.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(startswith(changes[0].path, root)); + assert_se(endswith(changes[0].path, "linked3.service")); + assert_se(streq(changes[0].source, "/opt/linked3.service")); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; +} + +static void test_default(const char *root) { + _cleanup_free_ char *def = NULL; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + const char *p; + + p = strjoina(root, "/usr/lib/systemd/system/test-default-real.target"); + assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/test-default.target"); + assert_se(symlink("test-default-real.target", p) >= 0); + + assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); + + assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "idontexist.target", false, &changes, &n_changes) == -ENOENT); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); + + assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "test-default.target", false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/default.target"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) >= 0); + assert_se(streq_ptr(def, "test-default-real.target")); +} + +static void test_add_dependency(const char *root) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + const char *p; + + p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-target.target"); + assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-target.target"); + assert_se(symlink("real-add-dependency-test-target.target", p) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-service.service"); + assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-service.service"); + assert_se(symlink("real-add-dependency-test-service.service", p) >= 0); + + assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; +} + +static void test_template_enable(const char *root) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + UnitFileState state; + const char *p; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/template@.service"); + assert_se(write_string_file(p, + "[Install]\n" + "DefaultInstance=def\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/template-symlink@.service"); + assert_se(symlink("template@.service", p) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@def.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), false, &changes, &n_changes) >= 0); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@foo.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template-symlink@quux.service"), false, &changes, &n_changes) >= 0); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@quux.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +} + +static void test_indirect(const char *root) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + UnitFileState state; + const char *p; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/indirecta.service"); + assert_se(write_string_file(p, + "[Install]\n" + "Also=indirectb.service\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/indirectb.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/indirectc.service"); + assert_se(symlink("indirecta.service", p) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); + + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; +} + +static void test_preset_and_list(const char *root) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0, i; + const char *p, *q; + UnitFileState state; + bool got_yes = false, got_no = false; + Iterator j; + UnitFileList *fl; + Hashmap *h; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/preset-no.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset"); + assert_se(write_string_file(p, + "enable *-yes.*\n" + "disable *\n", WRITE_STRING_FILE_CREATE) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, false, root, UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + + assert_se(n_changes > 0); + + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); + + for (i = 0; i < n_changes; i++) { + + if (changes[i].type == UNIT_FILE_SYMLINK) { + assert_se(streq(changes[i].source, "/usr/lib/systemd/system/preset-yes.service")); + assert_se(streq(changes[i].path, p)); + } else + assert_se(changes[i].type == UNIT_FILE_UNLINK); + } + + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(h = hashmap_new(&string_hash_ops)); + assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h, NULL, NULL) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); + q = strjoina(root, "/usr/lib/systemd/system/preset-no.service"); + + HASHMAP_FOREACH(fl, h, j) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, basename(fl->path), &state) >= 0); + assert_se(fl->state == state); + + if (streq(fl->path, p)) { + got_yes = true; + assert_se(fl->state == UNIT_FILE_ENABLED); + } else if (streq(fl->path, q)) { + got_no = true; + assert_se(fl->state == UNIT_FILE_DISABLED); + } else + assert_se(IN_SET(fl->state, UNIT_FILE_DISABLED, UNIT_FILE_STATIC, UNIT_FILE_INDIRECT)); + } + + unit_file_list_free(h); + + assert_se(got_yes && got_no); +} + +static void test_revert(const char *root) { + const char *p; + UnitFileState state; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + + assert(root); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "yy.service", NULL) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/xx.service"); + assert_se(write_string_file(p, "# Empty\n", WRITE_STRING_FILE_CREATE) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) >= 0); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", &state) >= 0 && state == UNIT_FILE_STATIC); + + /* Initially there's nothing to revert */ + assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service"); + assert_se(write_string_file(p, "# Empty override\n", WRITE_STRING_FILE_CREATE) >= 0); + + /* Revert the override file */ + assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service.d/dropin.conf"); + assert_se(mkdir_parents(p, 0755) >= 0); + assert_se(write_string_file(p, "# Empty dropin\n", WRITE_STRING_FILE_CREATE) >= 0); + + /* Revert the dropin file */ + assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(streq(changes[0].path, p)); + + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service.d"); + assert_se(changes[1].type == UNIT_FILE_UNLINK); + assert_se(streq(changes[1].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; +} + +static void test_preset_order(const char *root) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + const char *p; + UnitFileState state; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/prefix-1.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/prefix-2.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset"); + assert_se(write_string_file(p, + "enable prefix-1.service\n" + "disable prefix-*.service\n" + "enable prefix-2.service\n", WRITE_STRING_FILE_CREATE) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/prefix-1.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/prefix-1.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("prefix-2.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); +} + +int main(int argc, char *argv[]) { + char root[] = "/tmp/rootXXXXXX"; + const char *p; + + assert_se(mkdtemp(root)); + + p = strjoina(root, "/usr/lib/systemd/system/"); + assert_se(mkdir_p(p, 0755) >= 0); + + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/"); + assert_se(mkdir_p(p, 0755) >= 0); + + p = strjoina(root, "/run/systemd/system/"); + assert_se(mkdir_p(p, 0755) >= 0); + + p = strjoina(root, "/opt/"); + assert_se(mkdir_p(p, 0755) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system-preset/"); + assert_se(mkdir_p(p, 0755) >= 0); + + test_basic_mask_and_enable(root); + test_linked_units(root); + test_default(root); + test_add_dependency(root); + test_template_enable(root); + test_indirect(root); + test_preset_and_list(root); + test_preset_order(root); + test_revert(root); + + assert_se(rm_rf(root, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); + + return 0; +} diff --git a/src/test/test-install.c b/src/test/test-install.c index 5ee52e64cb..0ac85f040a 100644 --- a/src/test/test-install.c +++ b/src/test/test-install.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,8 +17,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <stdio.h> +#include <string.h> #include "install.h" @@ -46,17 +44,22 @@ int main(int argc, char* argv[]) { const char *const files2[] = { "/home/lennart/test.service", NULL }; UnitFileChange *changes = NULL; unsigned n_changes = 0; + UnitFileState state = 0; + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); h = hashmap_new(&string_hash_ops); - r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h); + r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL); assert_se(r == 0); HASHMAP_FOREACH(p, h, i) { - UnitFileState s; + UnitFileState s = _UNIT_FILE_STATE_INVALID; - s = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path)); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path), &s); - assert_se(p->state == s); + assert_se((r < 0 && p->state == UNIT_FILE_BAD) || + (p->state == s)); fprintf(stderr, "%s (%s)\n", p->path, @@ -65,12 +68,12 @@ int main(int argc, char* argv[]) { unit_file_list_free(h); - log_error("enable"); + log_info("/*** enable **/"); r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); assert_se(r >= 0); - log_error("enable2"); + log_info("/*** enable2 **/"); r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); assert_se(r >= 0); @@ -78,10 +81,11 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_ENABLED); - - log_error("disable"); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_ENABLED); + log_info("/*** disable ***/"); changes = NULL; n_changes = 0; @@ -91,39 +95,45 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_DISABLED); - log_error("mask"); + log_info("/*** mask ***/"); changes = NULL; n_changes = 0; r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); assert_se(r >= 0); - log_error("mask2"); + log_info("/*** mask2 ***/"); r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_MASKED); - log_error("unmask"); + log_info("/*** unmask ***/"); changes = NULL; n_changes = 0; r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); - log_error("unmask2"); + log_info("/*** unmask2 ***/"); r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_DISABLED); - log_error("mask"); + log_info("/*** mask ***/"); changes = NULL; n_changes = 0; @@ -133,24 +143,28 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_MASKED); - log_error("disable"); + log_info("/*** disable ***/"); changes = NULL; n_changes = 0; r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); - log_error("disable2"); + log_info("/*** disable2 ***/"); r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_MASKED); - log_error("umask"); + log_info("/*** umask ***/"); changes = NULL; n_changes = 0; @@ -160,9 +174,11 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_DISABLED); - log_error("enable files2"); + log_info("/*** enable files2 ***/"); changes = NULL; n_changes = 0; @@ -172,21 +188,24 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_ENABLED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_ENABLED); - log_error("disable files2"); + log_info("/*** disable files2 ***/"); changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); + r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r < 0); - log_error("link files2"); + log_info("/*** link files2 ***/"); changes = NULL; n_changes = 0; @@ -196,21 +215,24 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_LINKED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_LINKED); - log_error("disable files2"); + log_info("/*** disable files2 ***/"); changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); + r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r < 0); - log_error("link files2"); + log_info("/*** link files2 ***/"); changes = NULL; n_changes = 0; @@ -220,9 +242,11 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_LINKED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_LINKED); - log_error("reenable files2"); + log_info("/*** reenable files2 ***/"); changes = NULL; n_changes = 0; @@ -232,20 +256,23 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_ENABLED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_ENABLED); - log_error("disable files2"); + log_info("/*** disable files2 ***/"); changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); + r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); - log_error("preset files"); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r < 0); + log_info("/*** preset files ***/"); changes = NULL; n_changes = 0; @@ -255,7 +282,9 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0])) == UNIT_FILE_ENABLED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_ENABLED); return 0; } diff --git a/src/test/test-io-util.c b/src/test/test-io-util.c new file mode 100644 index 0000000000..10bd3833bc --- /dev/null +++ b/src/test/test-io-util.c @@ -0,0 +1,69 @@ +/*** + This file is part of systemd. + + Copyright 2010 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> +#include <stdlib.h> +#include <unistd.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" +#include "macro.h" + +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(void) { + test_sparse_write(); + + return 0; +} diff --git a/src/test/test-ipcrm.c b/src/test/test-ipcrm.c index 4944bf6ad9..551eba7215 100644 --- a/src/test/test-ipcrm.c +++ b/src/test/test-ipcrm.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,14 +17,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "clean-ipc.h" +#include "user-util.h" +#include "util.h" int main(int argc, char *argv[]) { uid_t uid; + int r; + const char* name = argv[1] ?: "nfsnobody"; - assert_se(argc == 2); - assert_se(parse_uid(argv[1], &uid) >= 0); + r = get_user_creds(&name, &uid, NULL, NULL, NULL); + if (r < 0) { + log_error_errno(r, "Failed to resolve \"%s\": %m", name); + return EXIT_FAILURE; + } - return clean_ipc(uid) < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + return clean_ipc_by_uid(uid) < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/test/test-job-type.c b/src/test/test-job-type.c index af0d76e894..7f0b9f253c 100644 --- a/src/test/test-job-type.c +++ b/src/test/test-job-type.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,8 +20,8 @@ #include <stdio.h> #include "job.h" -#include "unit.h" #include "service.h" +#include "unit.h" int main(int argc, char*argv[]) { JobType a, b, c, ab, bc, ab_c, bc_a, a_bc; diff --git a/src/test/test-json.c b/src/test/test-json.c deleted file mode 100644 index 1058c583c3..0000000000 --- a/src/test/test-json.c +++ /dev/null @@ -1,202 +0,0 @@ -/*-*- 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 "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); -} - -typedef void (*Test)(JsonVariant *); - -static void test_file(const char *data, Test test) { - _cleanup_json_variant_unref_ JsonVariant *v = NULL; - int r; - - r = json_parse(data, &v); - assert_se(r == 0); - assert_se(v != NULL); - assert_se(v->type == JSON_VARIANT_OBJECT); - - if (test) - test(v); -} - -static void test_1(JsonVariant *v) { - JsonVariant *p, *q; - unsigned i; - - /* 3 keys + 3 values */ - assert_se(v->size == 6); - - /* has k */ - p = json_variant_value(v, "k"); - assert_se(p && p->type == JSON_VARIANT_STRING); - - /* k equals v */ - assert_se(streq(json_variant_string(p), "v")); - - /* has foo */ - p = json_variant_value(v, "foo"); - assert_se(p && p->type == JSON_VARIANT_ARRAY && p->size == 3); - - /* check foo[0] = 1, foo[1] = 2, foo[2] = 3 */ - for (i = 0; i < 3; ++i) { - q = json_variant_element(p, i); - assert_se(q && q->type == JSON_VARIANT_INTEGER && json_variant_integer(q) == (i+1)); - } - - /* has bar */ - p = json_variant_value(v, "bar"); - assert_se(p && p->type == JSON_VARIANT_OBJECT && p->size == 2); - - /* zap is null */ - q = json_variant_value(p, "zap"); - assert_se(q && q->type == JSON_VARIANT_NULL); -} - -static void test_2(JsonVariant *v) { - JsonVariant *p, *q; - - /* 2 keys + 2 values */ - assert_se(v->size == 4); - - /* has mutant */ - p = json_variant_value(v, "mutant"); - assert_se(p && p->type == JSON_VARIANT_ARRAY && p->size == 4); - - /* mutant[0] == 1 */ - q = json_variant_element(p, 0); - assert_se(q && q->type == JSON_VARIANT_INTEGER && json_variant_integer(q) == 1); - - /* mutant[1] == null */ - q = json_variant_element(p, 1); - assert_se(q && q->type == JSON_VARIANT_NULL); - - /* mutant[2] == "1" */ - q = json_variant_element(p, 2); - assert_se(q && q->type == JSON_VARIANT_STRING && streq(json_variant_string(q), "1")); - - /* mutant[3] == JSON_VARIANT_OBJECT */ - q = json_variant_element(p, 3); - assert_se(q && q->type == JSON_VARIANT_OBJECT && q->size == 2); - - /* has 1 */ - p = json_variant_value(q, "1"); - assert_se(p && p->type == JSON_VARIANT_ARRAY && p->size == 2); - - /* "1"[0] == 1 */ - q = json_variant_element(p, 0); - assert_se(q && q->type == JSON_VARIANT_INTEGER && json_variant_integer(q) == 1); - - /* "1"[1] == "1" */ - q = json_variant_element(p, 1); - assert_se(q && q->type == JSON_VARIANT_STRING && streq(json_variant_string(q), "1")); - - /* has blah */ - p = json_variant_value(v, "blah"); - assert_se(p && p->type == JSON_VARIANT_REAL && fabs(json_variant_real(p) - 1.27) < 0.001); -} - -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); - - test_one("[1, 2]", JSON_ARRAY_OPEN, JSON_INTEGER, (intmax_t) 1, JSON_COMMA, JSON_INTEGER, (intmax_t) 2, JSON_ARRAY_CLOSE, JSON_END); - - test_file("{\"k\": \"v\", \"foo\": [1, 2, 3], \"bar\": {\"zap\": null}}", test_1); - test_file("{\"mutant\": [1, null, \"1\", {\"1\": [1, \"1\"]}], \"blah\": 1.27}", test_2); - - return 0; -} diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c index 34c49b969a..e28de9b37b 100644 --- a/src/test/test-libudev.c +++ b/src/test/test-libudev.c @@ -1,4 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ /*** This file is part of systemd. @@ -18,174 +17,147 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <unistd.h> #include <getopt.h> +#include <stdio.h> #include <sys/epoll.h> +#include <unistd.h> #include "libudev.h" + +#include "fd-util.h" +#include "log.h" +#include "stdio-util.h" +#include "string-util.h" #include "udev-util.h" #include "util.h" -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - static void print_device(struct udev_device *device) { const char *str; dev_t devnum; int count; struct udev_list_entry *list_entry; - printf("*** device: %p ***\n", device); + log_info("*** device: %p ***", device); str = udev_device_get_action(device); if (str != NULL) - printf("action: '%s'\n", str); + log_info("action: '%s'", str); str = udev_device_get_syspath(device); - printf("syspath: '%s'\n", str); + log_info("syspath: '%s'", str); str = udev_device_get_sysname(device); - printf("sysname: '%s'\n", str); + log_info("sysname: '%s'", str); str = udev_device_get_sysnum(device); if (str != NULL) - printf("sysnum: '%s'\n", str); + log_info("sysnum: '%s'", str); str = udev_device_get_devpath(device); - printf("devpath: '%s'\n", str); + log_info("devpath: '%s'", str); str = udev_device_get_subsystem(device); if (str != NULL) - printf("subsystem: '%s'\n", str); + log_info("subsystem: '%s'", str); str = udev_device_get_devtype(device); if (str != NULL) - printf("devtype: '%s'\n", str); + log_info("devtype: '%s'", str); str = udev_device_get_driver(device); if (str != NULL) - printf("driver: '%s'\n", str); + log_info("driver: '%s'", str); str = udev_device_get_devnode(device); if (str != NULL) - printf("devname: '%s'\n", str); + log_info("devname: '%s'", str); devnum = udev_device_get_devnum(device); if (major(devnum) > 0) - printf("devnum: %u:%u\n", major(devnum), minor(devnum)); + log_info("devnum: %u:%u", major(devnum), minor(devnum)); count = 0; udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) { - printf("link: '%s'\n", udev_list_entry_get_name(list_entry)); + log_info("link: '%s'", udev_list_entry_get_name(list_entry)); count++; } if (count > 0) - printf("found %i links\n", count); + log_info("found %i links", count); count = 0; udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) { - printf("property: '%s=%s'\n", + log_info("property: '%s=%s'", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); count++; } if (count > 0) - printf("found %i properties\n", count); + log_info("found %i properties", count); str = udev_device_get_property_value(device, "MAJOR"); if (str != NULL) - printf("MAJOR: '%s'\n", str); + log_info("MAJOR: '%s'", str); str = udev_device_get_sysattr_value(device, "dev"); if (str != NULL) - printf("attr{dev}: '%s'\n", str); - - printf("\n"); + log_info("attr{dev}: '%s'", str); } -static int test_device(struct udev *udev, const char *syspath) { +static void test_device(struct udev *udev, const char *syspath) { _cleanup_udev_device_unref_ struct udev_device *device; - printf("looking at device: %s\n", syspath); + log_info("looking at device: %s", syspath); device = udev_device_new_from_syspath(udev, syspath); - if (device == NULL) { - printf("no device found\n"); - return -1; - } - print_device(device); - - return 0; + if (device == NULL) + log_warning_errno(errno, "udev_device_new_from_syspath: %m"); + else + print_device(device); } -static int test_device_parents(struct udev *udev, const char *syspath) { +static void test_device_parents(struct udev *udev, const char *syspath) { _cleanup_udev_device_unref_ struct udev_device *device; struct udev_device *device_parent; - printf("looking at device: %s\n", syspath); + log_info("looking at device: %s", syspath); device = udev_device_new_from_syspath(udev, syspath); if (device == NULL) - return -1; + return; - printf("looking at parents\n"); + log_info("looking at parents"); device_parent = device; do { print_device(device_parent); device_parent = udev_device_get_parent(device_parent); } while (device_parent != NULL); - printf("looking at parents again\n"); + log_info("looking at parents again"); device_parent = device; do { print_device(device_parent); device_parent = udev_device_get_parent(device_parent); } while (device_parent != NULL); - - return 0; } -static int test_device_devnum(struct udev *udev) { +static void test_device_devnum(struct udev *udev) { dev_t devnum = makedev(1, 3); - struct udev_device *device; + _cleanup_udev_device_unref_ struct udev_device *device; - printf("looking up device: %u:%u\n", major(devnum), minor(devnum)); + log_info("looking up device: %u:%u", major(devnum), minor(devnum)); device = udev_device_new_from_devnum(udev, 'c', devnum); if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - return 0; + log_warning_errno(errno, "udev_device_new_from_devnum: %m"); + else + print_device(device); } -static int test_device_subsys_name(struct udev *udev) { - struct udev_device *device; - - printf("looking up device: 'block':'sda'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "block", "sda"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - - printf("looking up device: 'subsystem':'pci'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - - printf("looking up device: 'drivers':'scsi:sd'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "drivers", "scsi:sd"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); +static void test_device_subsys_name(struct udev *udev, const char *subsys, const char *dev) { + _cleanup_udev_device_unref_ struct udev_device *device; - printf("looking up device: 'module':'printk'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "module", "printk"); + log_info("looking up device: '%s:%s'", subsys, dev); + device = udev_device_new_from_subsystem_sysname(udev, subsys, dev); if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - return 0; + log_warning_errno(errno, "udev_device_new_from_subsystem_sysname: %m"); + else + print_device(device); } static int test_enumerate_print_list(struct udev_enumerate *enumerate) { @@ -198,63 +170,45 @@ static int test_enumerate_print_list(struct udev_enumerate *enumerate) { device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), udev_list_entry_get_name(list_entry)); if (device != NULL) { - printf("device: '%s' (%s)\n", - udev_device_get_syspath(device), - udev_device_get_subsystem(device)); + log_info("device: '%s' (%s)", + udev_device_get_syspath(device), + udev_device_get_subsystem(device)); udev_device_unref(device); count++; } } - printf("found %i devices\n\n", count); + log_info("found %i devices", count); return count; } -static int test_monitor(struct udev *udev) { - struct udev_monitor *udev_monitor = NULL; - int fd_ep; - int fd_udev = -1; - struct epoll_event ep_udev, ep_stdin; +static void test_monitor(struct udev *udev) { + _cleanup_udev_monitor_unref_ struct udev_monitor *udev_monitor; + _cleanup_close_ int fd_ep; + int fd_udev; + struct epoll_event ep_udev = { + .events = EPOLLIN, + }, ep_stdin = { + .events = EPOLLIN, + .data.fd = STDIN_FILENO, + }; fd_ep = epoll_create1(EPOLL_CLOEXEC); - if (fd_ep < 0) { - printf("error creating epoll fd: %m\n"); - goto out; - } + assert_se(fd_ep >= 0); udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); - if (udev_monitor == NULL) { - printf("no socket\n"); - goto out; - } + assert_se(udev_monitor != NULL); + fd_udev = udev_monitor_get_fd(udev_monitor); + ep_udev.data.fd = fd_udev; - if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) < 0 || - udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) < 0 || - udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") < 0) { - printf("filter failed\n"); - goto out; - } + assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) >= 0); + assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) >= 0); + assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") >= 0); - if (udev_monitor_enable_receiving(udev_monitor) < 0) { - printf("bind failed\n"); - goto out; - } + assert_se(udev_monitor_enable_receiving(udev_monitor) >= 0); - memzero(&ep_udev, sizeof(struct epoll_event)); - ep_udev.events = EPOLLIN; - ep_udev.data.fd = fd_udev; - if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) { - printf("fail to add fd to epoll: %m\n"); - goto out; - } - - memzero(&ep_stdin, sizeof(struct epoll_event)); - ep_stdin.events = EPOLLIN; - ep_stdin.data.fd = STDIN_FILENO; - if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) < 0) { - printf("fail to add fd to epoll: %m\n"); - goto out; - } + assert_se(epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) >= 0); + assert_se(epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) >= 0); for (;;) { int fdcount; @@ -263,7 +217,7 @@ static int test_monitor(struct udev *udev) { int i; printf("waiting for events from udev, press ENTER to exit\n"); - fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1); + fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1); printf("epoll fd count: %i\n", fdcount); for (i = 0; i < fdcount; i++) { @@ -277,36 +231,29 @@ static int test_monitor(struct udev *udev) { udev_device_unref(device); } else if (ev[i].data.fd == STDIN_FILENO && ev[i].events & EPOLLIN) { printf("exiting loop\n"); - goto out; + return; } } } -out: - if (fd_ep >= 0) - close(fd_ep); - udev_monitor_unref(udev_monitor); - return 0; } -static int test_queue(struct udev *udev) { +static void test_queue(struct udev *udev) { struct udev_queue *udev_queue; + bool empty; udev_queue = udev_queue_new(udev); - if (udev_queue == NULL) - return -1; - - if (udev_queue_get_queue_is_empty(udev_queue)) - printf("queue is empty\n"); + assert_se(udev_queue); + empty = udev_queue_get_queue_is_empty(udev_queue); + log_info("queue is %s", empty ? "empty" : "not empty"); udev_queue_unref(udev_queue); - return 0; } static int test_enumerate(struct udev *udev, const char *subsystem) { struct udev_enumerate *udev_enumerate; int r; - printf("enumerate '%s'\n", subsystem == NULL ? "<all>" : subsystem); + log_info("enumerate '%s'", subsystem == NULL ? "<all>" : subsystem); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -315,7 +262,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'net' + duplicated scan + null + zero\n"); + log_info("enumerate 'net' + duplicated scan + null + zero"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -335,7 +282,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'block'\n"); + log_info("enumerate 'block'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -349,7 +296,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'not block'\n"); + log_info("enumerate 'not block'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -358,7 +305,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'pci, mem, vc'\n"); + log_info("enumerate 'pci, mem, vc'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -369,7 +316,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'subsystem'\n"); + log_info("enumerate 'subsystem'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -377,7 +324,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'property IF_FS_*=filesystem'\n"); + log_info("enumerate 'property IF_FS_*=filesystem'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -395,32 +342,32 @@ static void test_hwdb(struct udev *udev, const char *modalias) { hwdb = udev_hwdb_new(udev); udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0)) - printf("'%s'='%s'\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); - printf("\n"); + log_info("'%s'='%s'", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); hwdb = udev_hwdb_unref(hwdb); assert_se(hwdb == NULL); } int main(int argc, char *argv[]) { - struct udev *udev = NULL; + _cleanup_udev_unref_ struct udev *udev = NULL; + bool arg_monitor = false; static const struct option options[] = { - { "syspath", required_argument, NULL, 'p' }, + { "syspath", required_argument, NULL, 'p' }, { "subsystem", required_argument, NULL, 's' }, - { "debug", no_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "monitor", no_argument, NULL, 'm' }, {} }; const char *syspath = "/devices/virtual/mem/null"; const char *subsystem = NULL; - char path[1024]; int c; udev = udev_new(); - printf("context: %p\n", udev); + log_info("context: %p", udev); if (udev == NULL) { - printf("no context\n"); + log_info("no context"); return 1; } @@ -442,14 +389,18 @@ int main(int argc, char *argv[]) { case 'h': printf("--debug --syspath= --subsystem= --help\n"); - goto out; + return EXIT_SUCCESS; case 'V': printf("%s\n", VERSION); - goto out; + return EXIT_SUCCESS; + + case 'm': + arg_monitor = true; + break; case '?': - goto out; + return EXIT_FAILURE; default: assert_not_reached("Unhandled option code."); @@ -457,14 +408,16 @@ int main(int argc, char *argv[]) { /* add sys path if needed */ - if (!startswith(syspath, "/sys")) { - snprintf(path, sizeof(path), "/sys/%s", syspath); - syspath = path; - } + if (!startswith(syspath, "/sys")) + syspath = strjoina("/sys/", syspath); test_device(udev, syspath); test_device_devnum(udev); - test_device_subsys_name(udev); + test_device_subsys_name(udev, "block", "sda"); + test_device_subsys_name(udev, "subsystem", "pci"); + test_device_subsys_name(udev, "drivers", "scsi:sd"); + test_device_subsys_name(udev, "module", "printk"); + test_device_parents(udev, syspath); test_enumerate(udev, subsystem); @@ -473,8 +426,8 @@ int main(int argc, char *argv[]) { test_hwdb(udev, "usb:v0D50p0011*"); - test_monitor(udev); -out: - udev_unref(udev); - return 0; + if (arg_monitor) + test_monitor(udev); + + return EXIT_SUCCESS; } diff --git a/src/test/test-list.c b/src/test/test-list.c index f6da1a7053..0ccd745cc9 100644 --- a/src/test/test-list.c +++ b/src/test/test-list.c @@ -99,6 +99,73 @@ int main(int argc, const char *argv[]) { assert_se(items[1].item_prev == &items[3]); assert_se(items[3].item_prev == NULL); + LIST_REMOVE(item, head, &items[1]); + assert_se(LIST_JUST_US(item, &items[1])); + + assert_se(items[0].item_next == NULL); + assert_se(items[2].item_next == &items[0]); + assert_se(items[3].item_next == &items[2]); + + assert_se(items[0].item_prev == &items[2]); + assert_se(items[2].item_prev == &items[3]); + assert_se(items[3].item_prev == NULL); + + LIST_INSERT_BEFORE(item, head, &items[2], &items[1]); + assert_se(items[0].item_next == NULL); + assert_se(items[2].item_next == &items[0]); + assert_se(items[1].item_next == &items[2]); + assert_se(items[3].item_next == &items[1]); + + assert_se(items[0].item_prev == &items[2]); + assert_se(items[2].item_prev == &items[1]); + assert_se(items[1].item_prev == &items[3]); + assert_se(items[3].item_prev == NULL); + + LIST_REMOVE(item, head, &items[0]); + assert_se(LIST_JUST_US(item, &items[0])); + + assert_se(items[2].item_next == NULL); + assert_se(items[1].item_next == &items[2]); + assert_se(items[3].item_next == &items[1]); + + assert_se(items[2].item_prev == &items[1]); + assert_se(items[1].item_prev == &items[3]); + assert_se(items[3].item_prev == NULL); + + LIST_INSERT_BEFORE(item, head, &items[3], &items[0]); + assert_se(items[2].item_next == NULL); + assert_se(items[1].item_next == &items[2]); + assert_se(items[3].item_next == &items[1]); + assert_se(items[0].item_next == &items[3]); + + assert_se(items[2].item_prev == &items[1]); + assert_se(items[1].item_prev == &items[3]); + assert_se(items[3].item_prev == &items[0]); + assert_se(items[0].item_prev == NULL); + assert_se(head == &items[0]); + + LIST_REMOVE(item, head, &items[0]); + assert_se(LIST_JUST_US(item, &items[0])); + + assert_se(items[2].item_next == NULL); + assert_se(items[1].item_next == &items[2]); + assert_se(items[3].item_next == &items[1]); + + assert_se(items[2].item_prev == &items[1]); + assert_se(items[1].item_prev == &items[3]); + assert_se(items[3].item_prev == NULL); + + LIST_INSERT_BEFORE(item, head, NULL, &items[0]); + assert_se(items[0].item_next == NULL); + assert_se(items[2].item_next == &items[0]); + assert_se(items[1].item_next == &items[2]); + assert_se(items[3].item_next == &items[1]); + + assert_se(items[0].item_prev == &items[2]); + assert_se(items[2].item_prev == &items[1]); + assert_se(items[1].item_prev == &items[3]); + assert_se(items[3].item_prev == NULL); + LIST_REMOVE(item, head, &items[0]); assert_se(LIST_JUST_US(item, &items[0])); diff --git a/src/test/test-locale-util.c b/src/test/test-locale-util.c index 9765075365..427c698d1d 100644 --- a/src/test/test-locale-util.c +++ b/src/test/test-locale-util.c @@ -19,8 +19,8 @@ #include "locale-util.h" -#include "strv.h" #include "macro.h" +#include "strv.h" static void test_get_locales(void) { _cleanup_strv_free_ char **locales = NULL; diff --git a/src/test/test-log.c b/src/test/test-log.c index 9dcfa2f274..55a2f9d23b 100644 --- a/src/test/test-log.c +++ b/src/test/test-log.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,9 +20,9 @@ #include <stddef.h> #include <unistd.h> +#include "formats-util.h" #include "log.h" #include "util.h" -#include "formats-util.h" int main(int argc, char* argv[]) { diff --git a/src/test/test-loopback.c b/src/test/test-loopback.c index c03bda4382..7b67337331 100644 --- a/src/test/test-loopback.c +++ b/src/test/test-loopback.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,11 +17,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <stdio.h> +#include <string.h> -#include "loopback-setup.h" #include "log.h" +#include "loopback-setup.h" int main(int argc, char* argv[]) { int r; @@ -31,8 +29,9 @@ int main(int argc, char* argv[]) { log_open(); log_parse_environment(); - if ((r = loopback_setup()) < 0) - fprintf(stderr, "loopback: %s\n", strerror(-r)); + r = loopback_setup(); + if (r < 0) + log_error("loopback: %m"); - return 0; + return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index 7d7e08dc5d..ff9f35cecd 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,9 +19,12 @@ #include <sys/socket.h> +#include "alloc-util.h" +#include "fd-util.h" #include "namespace.h" -#include "util.h" #include "process-util.h" +#include "string-util.h" +#include "util.h" static void test_tmpdir(const char *id, const char *A, const char *B) { _cleanup_free_ char *a, *b; @@ -68,8 +69,10 @@ static void test_netns(void) { int r, n = 0; siginfo_t si; - if (geteuid() > 0) - return; + if (geteuid() > 0) { + log_info("Skipping test: not root"); + exit(EXIT_TEST_SKIP); + } assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, s) >= 0); @@ -123,6 +126,9 @@ int main(int argc, char *argv[]) { char boot_id[SD_ID128_STRING_MAX]; _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *zz = NULL; + log_parse_environment(); + log_open(); + assert_se(sd_id128_get_boot(&bid) >= 0); sd_id128_to_string(bid, boot_id); diff --git a/src/test/test-netlink-manual.c b/src/test/test-netlink-manual.c index 2879d7450f..bc6dd0926c 100644 --- a/src/test/test-netlink-manual.c +++ b/src/test/test-netlink-manual.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,15 +18,16 @@ ***/ #include <arpa/inet.h> -#include <net/if.h> +#include <libkmod.h> #include <linux/ip.h> +#include <net/if.h> #include <linux/if_tunnel.h> -#include <libkmod.h> -#include "util.h" -#include "macro.h" #include "sd-netlink.h" +#include "macro.h" +#include "util.h" + static int load_module(const char *mod_name) { struct kmod_ctx *ctx; struct kmod_list *list = NULL, *l; @@ -69,10 +68,10 @@ static int test_tunnel_configure(sd_netlink *rtnl) { /* skip test if module cannot be loaded */ r = load_module("ipip"); - if(r < 0) + if (r < 0) return EXIT_TEST_SKIP; - if(getuid() != 0) + if (getuid() != 0) return EXIT_TEST_SKIP; /* IPIP tunnel */ @@ -100,7 +99,7 @@ static int test_tunnel_configure(sd_netlink *rtnl) { assert_se((m = sd_netlink_message_unref(m)) == NULL); r = load_module("sit"); - if(r < 0) + if (r < 0) return EXIT_TEST_SKIP; /* sit */ diff --git a/src/test/test-ns.c b/src/test/test-ns.c index 3050be9e9d..c4d4da6d05 100644 --- a/src/test/test-ns.c +++ b/src/test/test-ns.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,19 +20,24 @@ #include <stdlib.h> #include <unistd.h> -#include "namespace.h" #include "log.h" +#include "namespace.h" int main(int argc, char *argv[]) { const char * const writable[] = { "/home", + "-/home/lennart/projects/foobar", /* this should be masked automatically */ NULL }; const char * const readonly[] = { - "/", - "/usr", + /* "/", */ + /* "/usr", */ "/boot", + "/lib", + "/usr/lib", + "-/lib64", + "-/usr/lib64", NULL }; @@ -44,11 +47,12 @@ int main(int argc, char *argv[]) { }; char *root_directory; char *projects_directory; - int r; char tmp_dir[] = "/tmp/systemd-private-XXXXXX", var_tmp_dir[] = "/var/tmp/systemd-private-XXXXXX"; + log_set_max_level(LOG_DEBUG); + assert_se(mkdtemp(tmp_dir)); assert_se(mkdtemp(var_tmp_dir)); @@ -70,7 +74,8 @@ int main(int argc, char *argv[]) { (char **) inaccessible, tmp_dir, var_tmp_dir, - NULL, + true, + true, true, PROTECT_HOME_NO, PROTECT_SYSTEM_NO, diff --git a/src/test/test-nss.c b/src/test/test-nss.c new file mode 100644 index 0000000000..c43bda5917 --- /dev/null +++ b/src/test/test-nss.c @@ -0,0 +1,454 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 <dlfcn.h> +#include <stdlib.h> +#include <net/if.h> + +#include "log.h" +#include "nss-util.h" +#include "path-util.h" +#include "string-util.h" +#include "alloc-util.h" +#include "in-addr-util.h" +#include "hexdecoct.h" +#include "af-list.h" +#include "stdio-util.h" +#include "strv.h" +#include "errno-list.h" +#include "hostname-util.h" +#include "local-addresses.h" + +static const char* nss_status_to_string(enum nss_status status, char *buf, size_t buf_len) { + switch (status) { + case NSS_STATUS_TRYAGAIN: + return "NSS_STATUS_TRYAGAIN"; + case NSS_STATUS_UNAVAIL: + return "NSS_STATUS_UNAVAIL"; + case NSS_STATUS_NOTFOUND: + return "NSS_STATUS_NOTFOUND"; + case NSS_STATUS_SUCCESS: + return "NSS_STATUS_SUCCESS"; + case NSS_STATUS_RETURN: + return "NSS_STATUS_RETURN"; + default: + snprintf(buf, buf_len, "%i", status); + return buf; + } +}; + +static const char* af_to_string(int family, char *buf, size_t buf_len) { + const char *name; + + if (family == AF_UNSPEC) + return "*"; + + name = af_to_name(family); + if (name) + return name; + + snprintf(buf, buf_len, "%i", family); + return buf; +} + +static void* open_handle(const char* dir, const char* module, int flags) { + const char *path; + void *handle; + + if (dir) + path = strjoina(dir, "/.libs/libnss_", module, ".so.2"); + else + path = strjoina("libnss_", module, ".so.2"); + + handle = dlopen(path, flags); + assert_se(handle); + return handle; +} + +static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) { + const struct gaih_addrtuple *it; + int n = 0; + + for (it = tuples; it; it = it->next) { + _cleanup_free_ char *a = NULL; + union in_addr_union u; + int r; + char family_name[DECIMAL_STR_MAX(int)]; + char ifname[IF_NAMESIZE]; + + memcpy(&u, it->addr, 16); + r = in_addr_to_string(it->family, &u, &a); + assert_se(r == 0 || r == -EAFNOSUPPORT); + if (r == -EAFNOSUPPORT) + assert_se((a = hexmem(it->addr, 16))); + + if (it->scopeid == 0) + goto numerical_index; + + if (if_indextoname(it->scopeid, ifname) == NULL) { + log_warning("if_indextoname(%d) failed: %m", it->scopeid); + numerical_index: + xsprintf(ifname, "%i", it->scopeid); + }; + + log_info(" \"%s\" %s %s %%%s", + it->name, + af_to_string(it->family, family_name, sizeof family_name), + a, + ifname); + n ++; + } + return n; +} + +static void print_struct_hostent(struct hostent *host, const char *canon) { + char **s; + + log_info(" \"%s\"", host->h_name); + STRV_FOREACH(s, host->h_aliases) + log_info(" alias \"%s\"", *s); + STRV_FOREACH(s, host->h_addr_list) { + union in_addr_union u; + _cleanup_free_ char *a = NULL; + char family_name[DECIMAL_STR_MAX(int)]; + int r; + + assert_se((unsigned) host->h_length == FAMILY_ADDRESS_SIZE(host->h_addrtype)); + memcpy(&u, *s, host->h_length); + r = in_addr_to_string(host->h_addrtype, &u, &a); + assert_se(r == 0); + log_info(" %s %s", + af_to_string(host->h_addrtype, family_name, sizeof family_name), + a); + } + if (canon) + log_info(" canonical: \"%s\"", canon); +} + +static void test_gethostbyname4_r(void *handle, const char *module, const char *name) { + const char *fname; + _nss_gethostbyname4_r_t f; + char buffer[2000]; + struct gaih_addrtuple *pat = NULL; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl, + and will access this variable through *ttlp, + so we need to set it to something. + I'm not sure if this is a bug in nss-dns + or not. */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + int n; + + fname = strjoina("_nss_", module, "_gethostbyname4_r"); + f = dlsym(handle, fname); + log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f); + assert_se(f); + + status = f(name, &pat, buffer, sizeof buffer, &errno1, &errno2, &ttl); + if (status == NSS_STATUS_SUCCESS) { + log_info("%s(\"%s\") → status=%s%-20spat=buffer+0x%tx errno=%d/%s h_errno=%d/%s ttl=%"PRIi32, + fname, name, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + pat ? (char*) pat - buffer : 0, + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2), + ttl); + n = print_gaih_addrtuples(pat); + } else { + log_info("%s(\"%s\") → status=%s%-20spat=0x%p errno=%d/%s h_errno=%d/%s", + fname, name, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + pat, + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2)); + n = 0; + } + + if (STR_IN_SET(module, "resolve", "mymachines") && status == NSS_STATUS_UNAVAIL) + return; + + if (STR_IN_SET(module, "myhostname", "resolve") && streq(name, "localhost")) { + assert_se(status == NSS_STATUS_SUCCESS); + assert_se(n == 2); + } +} + + +static void test_gethostbyname3_r(void *handle, const char *module, const char *name, int af) { + const char *fname; + _nss_gethostbyname3_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl, + and will access this variable through *ttlp, + so we need to set it to something. + I'm not sure if this is a bug in nss-dns + or not. */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + char *canon; + char family_name[DECIMAL_STR_MAX(int)]; + + fname = strjoina("_nss_", module, "_gethostbyname3_r"); + f = dlsym(handle, fname); + log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f); + assert_se(f); + + status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl, &canon); + log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32, + fname, name, af_to_string(af, family_name, sizeof family_name), + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2), + ttl); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, canon); +} + +static void test_gethostbyname2_r(void *handle, const char *module, const char *name, int af) { + const char *fname; + _nss_gethostbyname2_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + char family_name[DECIMAL_STR_MAX(int)]; + + fname = strjoina("_nss_", module, "_gethostbyname2_r"); + f = dlsym(handle, fname); + log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f); + assert_se(f); + + status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2); + log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s", + fname, name, af_to_string(af, family_name, sizeof family_name), + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2)); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, NULL); +} + +static void test_gethostbyname_r(void *handle, const char *module, const char *name) { + const char *fname; + _nss_gethostbyname_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + + fname = strjoina("_nss_", module, "_gethostbyname_r"); + f = dlsym(handle, fname); + log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f); + assert_se(f); + + status = f(name, &host, buffer, sizeof buffer, &errno1, &errno2); + log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s", + fname, name, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2)); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, NULL); +} + +static void test_gethostbyaddr2_r(void *handle, + const char *module, + const void* addr, socklen_t len, + int af) { + + const char *fname; + _nss_gethostbyaddr2_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + int32_t ttl = INT32_MAX; + _cleanup_free_ char *addr_pretty = NULL; + + fname = strjoina("_nss_", module, "_gethostbyaddr2_r"); + f = dlsym(handle, fname); + + log_full_errno(f ? LOG_DEBUG : LOG_INFO, errno, + "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f); + if (!f) + return; + + assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0); + + status = f(addr, len, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl); + log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32, + fname, addr_pretty, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2), + ttl); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, NULL); +} + +static void test_gethostbyaddr_r(void *handle, + const char *module, + const void* addr, socklen_t len, + int af) { + + const char *fname; + _nss_gethostbyaddr_r_t f; + char buffer[2000]; + int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */ + enum nss_status status; + char pretty_status[DECIMAL_STR_MAX(enum nss_status)]; + struct hostent host; + _cleanup_free_ char *addr_pretty = NULL; + + fname = strjoina("_nss_", module, "_gethostbyaddr_r"); + f = dlsym(handle, fname); + + log_full_errno(f ? LOG_DEBUG : LOG_INFO, errno, + "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f); + if (!f) + return; + + assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0); + + status = f(addr, len, af, &host, buffer, sizeof buffer, &errno1, &errno2); + log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s", + fname, addr_pretty, + nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n", + errno1, errno_to_name(errno1) ?: "---", + errno2, hstrerror(errno2)); + if (status == NSS_STATUS_SUCCESS) + print_struct_hostent(&host, NULL); +} + +static void test_byname(void *handle, const char *module, const char *name) { + test_gethostbyname4_r(handle, module, name); + puts(""); + + test_gethostbyname3_r(handle, module, name, AF_INET); + puts(""); + test_gethostbyname3_r(handle, module, name, AF_INET6); + puts(""); + test_gethostbyname3_r(handle, module, name, AF_UNSPEC); + puts(""); + test_gethostbyname3_r(handle, module, name, AF_LOCAL); + puts(""); + + test_gethostbyname2_r(handle, module, name, AF_INET); + puts(""); + test_gethostbyname2_r(handle, module, name, AF_INET6); + puts(""); + test_gethostbyname2_r(handle, module, name, AF_UNSPEC); + puts(""); + test_gethostbyname2_r(handle, module, name, AF_LOCAL); + puts(""); + + test_gethostbyname_r(handle, module, name); + puts(""); +} + +static void test_byaddr(void *handle, + const char *module, + const void* addr, socklen_t len, + int af) { + test_gethostbyaddr2_r(handle, module, addr, len, af); + puts(""); + + test_gethostbyaddr_r(handle, module, addr, len, af); + puts(""); +} + +#ifdef HAVE_MYHOSTNAME +# define MODULE1 "myhostname\0" +#else +# define MODULE1 +#endif +#ifdef HAVE_RESOLVED +# define MODULE2 "resolve\0" +#else +# define MODULE2 +#endif +#ifdef HAVE_MACHINED +# define MODULE3 "mymachines\0" +#else +# define MODULE3 +#endif +#define MODULE4 "dns\0" + +int main(int argc, char **argv) { + _cleanup_free_ char *dir = NULL, *hostname = NULL; + const char *module; + + const uint32_t local_address_ipv4 = htobe32(0x7F000001); + const uint32_t local_address_ipv4_2 = htobe32(0x7F000002); + _cleanup_free_ struct local_address *addresses = NULL; + int n_addresses; + + log_set_max_level(LOG_INFO); + log_parse_environment(); + + dir = dirname_malloc(argv[0]); + assert_se(dir); + + hostname = gethostname_malloc(); + assert_se(hostname); + + n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses); + if (n_addresses < 0) { + log_info_errno(n_addresses, "Failed to query local addresses: %m"); + n_addresses = 0; + } + + NULSTR_FOREACH(module, MODULE1 MODULE2 MODULE3 MODULE4) { + void *handle; + const char *name; + int i; + + log_info("======== %s ========", module); + + handle = open_handle(streq(module, "dns") ? NULL : dir, + module, + RTLD_LAZY|RTLD_NODELETE); + NULSTR_FOREACH(name, "localhost\0" "gateway\0" "foo_no_such_host\0") + test_byname(handle, module, name); + + test_byname(handle, module, hostname); + + test_byaddr(handle, module, &local_address_ipv4, sizeof local_address_ipv4, AF_INET); + test_byaddr(handle, module, &local_address_ipv4_2, sizeof local_address_ipv4_2, AF_INET); + test_byaddr(handle, module, &in6addr_loopback, sizeof in6addr_loopback, AF_INET6); + + for (i = 0; i < n_addresses; i++) + test_byaddr(handle, module, + &addresses[i].address, + FAMILY_ADDRESS_SIZE(addresses[i].family), + addresses[i].family); + + dlclose(handle); + + log_info(" "); + } + + return EXIT_SUCCESS; +} diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c new file mode 100644 index 0000000000..d08014100b --- /dev/null +++ b/src/test/test-parse-util.c @@ -0,0 +1,547 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2013 Thomas H.P. Andersen + + 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 <locale.h> +#include <math.h> + +#include "log.h" +#include "parse-util.h" + +static void test_parse_boolean(void) { + assert_se(parse_boolean("1") == 1); + assert_se(parse_boolean("y") == 1); + assert_se(parse_boolean("Y") == 1); + assert_se(parse_boolean("yes") == 1); + assert_se(parse_boolean("YES") == 1); + assert_se(parse_boolean("true") == 1); + assert_se(parse_boolean("TRUE") == 1); + assert_se(parse_boolean("on") == 1); + assert_se(parse_boolean("ON") == 1); + + assert_se(parse_boolean("0") == 0); + assert_se(parse_boolean("n") == 0); + assert_se(parse_boolean("N") == 0); + assert_se(parse_boolean("no") == 0); + assert_se(parse_boolean("NO") == 0); + assert_se(parse_boolean("false") == 0); + assert_se(parse_boolean("FALSE") == 0); + assert_se(parse_boolean("off") == 0); + assert_se(parse_boolean("OFF") == 0); + + assert_se(parse_boolean("garbage") < 0); + assert_se(parse_boolean("") < 0); + assert_se(parse_boolean("full") < 0); +} + +static void test_parse_pid(void) { + int r; + pid_t pid; + + r = parse_pid("100", &pid); + assert_se(r == 0); + assert_se(pid == 100); + + r = parse_pid("0x7FFFFFFF", &pid); + assert_se(r == 0); + assert_se(pid == 2147483647); + + pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ + r = parse_pid("0", &pid); + assert_se(r == -ERANGE); + assert_se(pid == 65); + + pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ + r = parse_pid("-100", &pid); + assert_se(r == -ERANGE); + assert_se(pid == 65); + + pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ + r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid); + assert_se(r == -ERANGE); + assert_se(pid == 65); + + r = parse_pid("junk", &pid); + assert_se(r == -EINVAL); +} + +static void test_parse_mode(void) { + mode_t m; + + assert_se(parse_mode("-1", &m) < 0); + assert_se(parse_mode("", &m) < 0); + assert_se(parse_mode("888", &m) < 0); + assert_se(parse_mode("77777", &m) < 0); + + assert_se(parse_mode("544", &m) >= 0 && m == 0544); + assert_se(parse_mode("777", &m) >= 0 && m == 0777); + assert_se(parse_mode("7777", &m) >= 0 && m == 07777); + assert_se(parse_mode("0", &m) >= 0 && m == 0); +} + +static void test_parse_size(void) { + uint64_t bytes; + + assert_se(parse_size("111", 1024, &bytes) == 0); + assert_se(bytes == 111); + + assert_se(parse_size("111.4", 1024, &bytes) == 0); + assert_se(bytes == 111); + + assert_se(parse_size(" 112 B", 1024, &bytes) == 0); + assert_se(bytes == 112); + + assert_se(parse_size(" 112.6 B", 1024, &bytes) == 0); + assert_se(bytes == 112); + + assert_se(parse_size("3.5 K", 1024, &bytes) == 0); + assert_se(bytes == 3*1024 + 512); + + assert_se(parse_size("3. K", 1024, &bytes) == 0); + assert_se(bytes == 3*1024); + + assert_se(parse_size("3.0 K", 1024, &bytes) == 0); + assert_se(bytes == 3*1024); + + assert_se(parse_size("3. 0 K", 1024, &bytes) == -EINVAL); + + assert_se(parse_size(" 4 M 11.5K", 1024, &bytes) == 0); + assert_se(bytes == 4*1024*1024 + 11 * 1024 + 512); + + assert_se(parse_size("3B3.5G", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("3.5G3B", 1024, &bytes) == 0); + assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 3); + + assert_se(parse_size("3.5G 4B", 1024, &bytes) == 0); + assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 4); + + assert_se(parse_size("3B3G4T", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("4T3G3B", 1024, &bytes) == 0); + assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3); + + assert_se(parse_size(" 4 T 3 G 3 B", 1024, &bytes) == 0); + assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3); + + assert_se(parse_size("12P", 1024, &bytes) == 0); + assert_se(bytes == 12ULL * 1024*1024*1024*1024*1024); + + assert_se(parse_size("12P12P", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("3E 2P", 1024, &bytes) == 0); + assert_se(bytes == (3 * 1024 + 2ULL) * 1024*1024*1024*1024*1024); + + assert_se(parse_size("12X", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("12.5X", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("12.5e3", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("1024E", 1024, &bytes) == -ERANGE); + assert_se(parse_size("-1", 1024, &bytes) == -ERANGE); + assert_se(parse_size("-1024E", 1024, &bytes) == -ERANGE); + + assert_se(parse_size("-1024P", 1024, &bytes) == -ERANGE); + + assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE); +} + +static void test_parse_range(void) { + unsigned lower, upper; + + /* Successful cases */ + assert_se(parse_range("111", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 111); + + assert_se(parse_range("111-123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + assert_se(parse_range("123-111", &lower, &upper) == 0); + assert_se(lower == 123); + assert_se(upper == 111); + + assert_se(parse_range("123-123", &lower, &upper) == 0); + assert_se(lower == 123); + assert_se(upper == 123); + + assert_se(parse_range("0", &lower, &upper) == 0); + assert_se(lower == 0); + assert_se(upper == 0); + + assert_se(parse_range("0-15", &lower, &upper) == 0); + assert_se(lower == 0); + assert_se(upper == 15); + + assert_se(parse_range("15-0", &lower, &upper) == 0); + assert_se(lower == 15); + assert_se(upper == 0); + + assert_se(parse_range("128-65535", &lower, &upper) == 0); + assert_se(lower == 128); + assert_se(upper == 65535); + + assert_se(parse_range("1024-4294967295", &lower, &upper) == 0); + assert_se(lower == 1024); + assert_se(upper == 4294967295); + + /* Leading whitespace is acceptable */ + assert_se(parse_range(" 111", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 111); + + assert_se(parse_range(" 111-123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + assert_se(parse_range("111- 123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + assert_se(parse_range("\t111-\t123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + assert_se(parse_range(" \t 111- \t 123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + /* Error cases, make sure they fail as expected */ + lower = upper = 9999; + assert_se(parse_range("111garbage", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("garbage111", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("garbage", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123garbage", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111garbage-123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Empty string */ + lower = upper = 9999; + assert_se(parse_range("", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* 111--123 will pass -123 to safe_atou which returns -ERANGE for negative */ + assert_se(parse_range("111--123", &lower, &upper) == -ERANGE); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("-111-123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111.4-123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123.4", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111,4-123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123,4", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Error on trailing dash */ + assert_se(parse_range("111-", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111--", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111- ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Whitespace is not a separator */ + assert_se(parse_range("111 123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111\t123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111 \t 123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Trailing whitespace is invalid (from safe_atou) */ + assert_se(parse_range("111 ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123 ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111 -123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111 -123 ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111\t-123\t", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111 \t -123 \t ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Out of the "unsigned" range, this is 1<<64 */ + assert_se(parse_range("0-18446744073709551616", &lower, &upper) == -ERANGE); + assert_se(lower == 9999); + assert_se(upper == 9999); +} + +static void test_safe_atolli(void) { + int r; + long long l; + + r = safe_atolli("12345", &l); + assert_se(r == 0); + assert_se(l == 12345); + + r = safe_atolli(" 12345", &l); + assert_se(r == 0); + assert_se(l == 12345); + + r = safe_atolli("-12345", &l); + assert_se(r == 0); + assert_se(l == -12345); + + r = safe_atolli(" -12345", &l); + assert_se(r == 0); + assert_se(l == -12345); + + r = safe_atolli("12345678901234567890", &l); + assert_se(r == -ERANGE); + + r = safe_atolli("-12345678901234567890", &l); + assert_se(r == -ERANGE); + + r = safe_atolli("junk", &l); + assert_se(r == -EINVAL); +} + +static void test_safe_atou16(void) { + int r; + uint16_t l; + + r = safe_atou16("12345", &l); + assert_se(r == 0); + assert_se(l == 12345); + + r = safe_atou16(" 12345", &l); + assert_se(r == 0); + assert_se(l == 12345); + + r = safe_atou16("123456", &l); + assert_se(r == -ERANGE); + + r = safe_atou16("-1", &l); + assert_se(r == -ERANGE); + + r = safe_atou16(" -1", &l); + assert_se(r == -ERANGE); + + r = safe_atou16("junk", &l); + assert_se(r == -EINVAL); +} + +static void test_safe_atoi16(void) { + int r; + int16_t l; + + r = safe_atoi16("-12345", &l); + assert_se(r == 0); + assert_se(l == -12345); + + r = safe_atoi16(" -12345", &l); + assert_se(r == 0); + assert_se(l == -12345); + + r = safe_atoi16("32767", &l); + assert_se(r == 0); + assert_se(l == 32767); + + r = safe_atoi16(" 32767", &l); + assert_se(r == 0); + assert_se(l == 32767); + + r = safe_atoi16("36536", &l); + assert_se(r == -ERANGE); + + r = safe_atoi16("-32769", &l); + assert_se(r == -ERANGE); + + r = safe_atoi16("junk", &l); + assert_se(r == -EINVAL); +} + +static void test_safe_atod(void) { + int r; + double d; + char *e; + + r = safe_atod("junk", &d); + assert_se(r == -EINVAL); + + r = safe_atod("0.2244", &d); + assert_se(r == 0); + assert_se(fabs(d - 0.2244) < 0.000001); + + r = safe_atod("0,5", &d); + assert_se(r == -EINVAL); + + errno = 0; + strtod("0,5", &e); + assert_se(*e == ','); + + /* Check if this really is locale independent */ + if (setlocale(LC_NUMERIC, "de_DE.utf8")) { + + r = safe_atod("0.2244", &d); + assert_se(r == 0); + assert_se(fabs(d - 0.2244) < 0.000001); + + r = safe_atod("0,5", &d); + assert_se(r == -EINVAL); + + errno = 0; + assert_se(fabs(strtod("0,5", &e) - 0.5) < 0.00001); + } + + /* And check again, reset */ + assert_se(setlocale(LC_NUMERIC, "C")); + + r = safe_atod("0.2244", &d); + assert_se(r == 0); + assert_se(fabs(d - 0.2244) < 0.000001); + + r = safe_atod("0,5", &d); + assert_se(r == -EINVAL); + + errno = 0; + strtod("0,5", &e); + assert_se(*e == ','); +} + +static void test_parse_percent(void) { + assert_se(parse_percent("") == -EINVAL); + assert_se(parse_percent("foo") == -EINVAL); + assert_se(parse_percent("0") == -EINVAL); + assert_se(parse_percent("50") == -EINVAL); + assert_se(parse_percent("100") == -EINVAL); + assert_se(parse_percent("-1") == -EINVAL); + assert_se(parse_percent("0%") == 0); + assert_se(parse_percent("55%") == 55); + assert_se(parse_percent("100%") == 100); + assert_se(parse_percent("-7%") == -ERANGE); + assert_se(parse_percent("107%") == -ERANGE); + assert_se(parse_percent("%") == -EINVAL); + assert_se(parse_percent("%%") == -EINVAL); + assert_se(parse_percent("%1") == -EINVAL); + assert_se(parse_percent("1%%") == -EINVAL); +} + +static void test_parse_percent_unbounded(void) { + assert_se(parse_percent_unbounded("101%") == 101); + assert_se(parse_percent_unbounded("400%") == 400); +} + +static void test_parse_nice(void) { + int n; + + assert_se(parse_nice("0", &n) >= 0 && n == 0); + assert_se(parse_nice("+0", &n) >= 0 && n == 0); + assert_se(parse_nice("-1", &n) >= 0 && n == -1); + assert_se(parse_nice("-2", &n) >= 0 && n == -2); + assert_se(parse_nice("1", &n) >= 0 && n == 1); + assert_se(parse_nice("2", &n) >= 0 && n == 2); + assert_se(parse_nice("+1", &n) >= 0 && n == 1); + assert_se(parse_nice("+2", &n) >= 0 && n == 2); + assert_se(parse_nice("-20", &n) >= 0 && n == -20); + assert_se(parse_nice("19", &n) >= 0 && n == 19); + assert_se(parse_nice("+19", &n) >= 0 && n == 19); + + + assert_se(parse_nice("", &n) == -EINVAL); + assert_se(parse_nice("-", &n) == -EINVAL); + assert_se(parse_nice("+", &n) == -EINVAL); + assert_se(parse_nice("xx", &n) == -EINVAL); + assert_se(parse_nice("-50", &n) == -ERANGE); + assert_se(parse_nice("50", &n) == -ERANGE); + assert_se(parse_nice("+50", &n) == -ERANGE); + assert_se(parse_nice("-21", &n) == -ERANGE); + assert_se(parse_nice("20", &n) == -ERANGE); + assert_se(parse_nice("+20", &n) == -ERANGE); +} + +int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); + + test_parse_boolean(); + test_parse_pid(); + test_parse_mode(); + test_parse_size(); + test_parse_range(); + test_safe_atolli(); + test_safe_atou16(); + test_safe_atoi16(); + test_safe_atod(); + test_parse_percent(); + test_parse_percent_unbounded(); + test_parse_nice(); + + return 0; +} diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c index aa4bac6cdd..096326d176 100644 --- a/src/test/test-path-lookup.c +++ b/src/test/test-path-lookup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,40 +17,47 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <stdlib.h> #include <sys/stat.h> -#include "path-lookup.h" #include "log.h" -#include "strv.h" +#include "path-lookup.h" #include "rm-rf.h" +#include "string-util.h" +#include "strv.h" -static void test_paths(ManagerRunningAs running_as, bool personal) { +static void test_paths(UnitFileScope scope) { char template[] = "/tmp/test-path-lookup.XXXXXXX"; - _cleanup_lookup_paths_free_ LookupPaths lp = {}; - char *exists, *not; + _cleanup_lookup_paths_free_ LookupPaths lp_without_env = {}; + _cleanup_lookup_paths_free_ LookupPaths lp_with_env = {}; + char *systemd_unit_path; 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(unsetenv("SYSTEMD_UNIT_PATH") == 0); + assert_se(lookup_paths_init(&lp_without_env, scope, 0, NULL) >= 0); + assert_se(!strv_isempty(lp_without_env.search_path)); + assert_se(lookup_paths_reduce(&lp_without_env) >= 0); - assert_se(!strv_isempty(lp.unit_path)); - assert_se(strv_contains(lp.unit_path, exists)); - assert_se(strv_contains(lp.unit_path, not)); + systemd_unit_path = strjoina(template, "/systemd-unit-path"); + assert_se(setenv("SYSTEMD_UNIT_PATH", systemd_unit_path, 1) == 0); + assert_se(lookup_paths_init(&lp_with_env, scope, 0, NULL) == 0); + assert_se(strv_length(lp_with_env.search_path) == 1); + assert_se(streq(lp_with_env.search_path[0], systemd_unit_path)); + assert_se(lookup_paths_reduce(&lp_with_env) >= 0); + assert_se(strv_length(lp_with_env.search_path) == 0); assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } -static void print_generator_paths(ManagerRunningAs running_as) { +static void print_generator_binary_paths(UnitFileScope scope) { _cleanup_strv_free_ char **paths; char **dir; - log_info("Generators dirs (%s):", running_as == MANAGER_SYSTEM ? "system" : "user"); + log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user"); - paths = generator_paths(running_as); + paths = generator_binary_paths(scope); STRV_FOREACH(dir, paths) log_info(" %s", *dir); } @@ -62,13 +67,12 @@ int main(int argc, char **argv) { log_parse_environment(); log_open(); - test_paths(MANAGER_SYSTEM, false); - test_paths(MANAGER_SYSTEM, true); - test_paths(MANAGER_USER, false); - test_paths(MANAGER_USER, true); + test_paths(UNIT_FILE_SYSTEM); + test_paths(UNIT_FILE_USER); + test_paths(UNIT_FILE_GLOBAL); - print_generator_paths(MANAGER_SYSTEM); - print_generator_paths(MANAGER_USER); + print_generator_binary_paths(UNIT_FILE_SYSTEM); + print_generator_binary_paths(UNIT_FILE_USER); return EXIT_SUCCESS; } diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index fce4e81a09..0b10d8e25e 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,14 +18,18 @@ ***/ #include <stdio.h> -#include <unistd.h> #include <sys/mount.h> +#include <unistd.h> -#include "path-util.h" -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "macro.h" -#include "strv.h" +#include "mount-util.h" +#include "path-util.h" #include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" #define test_path_compare(a, b, result) { \ assert_se(path_compare(a, b) == result); \ @@ -75,20 +77,6 @@ static void test_path(void) { assert_se(streq(basename("/aa///file..."), "file...")); assert_se(streq(basename("file.../"), "")); -#define test_parent(x, y) { \ - _cleanup_free_ char *z = NULL; \ - int r = path_get_parent(x, &z); \ - printf("expected: %s\n", y ? y : "error"); \ - printf("actual: %s\n", r<0 ? "error" : z); \ - assert_se((y==NULL) ^ (r==0)); \ - assert_se(y==NULL || path_equal(z, y)); \ - } - - test_parent("./aa/bb/../file.da.", "./aa/bb/.."); - test_parent("/aa///.file", "/aa///"); - test_parent("/aa///file...", "/aa///"); - test_parent("file.../", NULL); - fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY); assert_se(fd >= 0); assert_se(fd_is_mount_point(fd, "/", 0) > 0); @@ -102,34 +90,43 @@ static void test_path(void) { assert_se(path_equal(path_kill_slashes(p2), "/aaa/./ccc")); assert_se(path_equal(path_kill_slashes(p3), "/./")); } + + assert_se(PATH_IN_SET("/bin", "/", "/bin", "/foo")); + assert_se(PATH_IN_SET("/bin", "/bin")); + assert_se(PATH_IN_SET("/bin", "/foo/bar", "/bin")); + assert_se(PATH_IN_SET("/", "/", "/", "/foo/bar")); + assert_se(!PATH_IN_SET("/", "/abc", "/def")); + + assert_se(path_equal_ptr(NULL, NULL)); + assert_se(path_equal_ptr("/a", "/a")); + assert_se(!path_equal_ptr("/a", "/b")); + assert_se(!path_equal_ptr("/a", NULL)); + assert_se(!path_equal_ptr(NULL, "/a")); } -static void test_find_binary(const char *self, bool local) { +static void test_find_binary(const char *self) { char *p; - assert_se(find_binary("/bin/sh", local, &p) == 0); + assert_se(find_binary("/bin/sh", &p) == 0); puts(p); - assert_se(streq(p, "/bin/sh")); + assert_se(path_equal(p, "/bin/sh")); free(p); - assert_se(find_binary(self, local, &p) == 0); + assert_se(find_binary(self, &p) == 0); puts(p); - assert_se(endswith(p, "/test-path-util")); + /* libtool might prefix the binary name with "lt-" */ + assert_se(endswith(p, "/lt-test-path-util") || endswith(p, "/test-path-util")); assert_se(path_is_absolute(p)); free(p); - assert_se(find_binary("sh", local, &p) == 0); + assert_se(find_binary("sh", &p) == 0); puts(p); assert_se(endswith(p, "/sh")); assert_se(path_is_absolute(p)); free(p); - assert_se(find_binary("xxxx-xxxx", local, &p) == -ENOENT); - - assert_se(find_binary("/some/dir/xxxx-xxxx", local, &p) == - (local ? -ENOENT : 0)); - if (!local) - free(p); + assert_se(find_binary("xxxx-xxxx", &p) == -ENOENT); + assert_se(find_binary("/some/dir/xxxx-xxxx", &p) == -ENOENT); } static void test_prefixes(void) { @@ -210,9 +207,10 @@ static void test_fsck_exists(void) { unsetenv("PATH"); /* fsck.minix is provided by util-linux and will probably exist. */ - assert_se(fsck_exists("minix") == 0); + assert_se(fsck_exists("minix") == 1); - assert_se(fsck_exists("AbCdE") == -ENOENT); + assert_se(fsck_exists("AbCdE") == 0); + assert_se(fsck_exists("/../bin/") == 0); } static void test_make_relative(void) { @@ -448,10 +446,91 @@ static void test_path_is_mount_point(void) { assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0); } +static void test_file_in_same_dir(void) { + char *t; + + t = file_in_same_dir("/", "a"); + assert_se(streq(t, "/a")); + free(t); + + t = file_in_same_dir("/", "/a"); + assert_se(streq(t, "/a")); + free(t); + + t = file_in_same_dir("", "a"); + assert_se(streq(t, "a")); + free(t); + + t = file_in_same_dir("a/", "a"); + assert_se(streq(t, "a/a")); + free(t); + + t = file_in_same_dir("bar/foo", "bar"); + assert_se(streq(t, "bar/bar")); + free(t); +} + +static void test_filename_is_valid(void) { + char foo[FILENAME_MAX+2]; + int i; + + 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_valid(foo)); + + assert_se(filename_is_valid("foo_bar-333")); + assert_se(filename_is_valid("o.o")); +} + +static void test_hidden_or_backup_file(void) { + assert_se(hidden_or_backup_file(".hidden")); + assert_se(hidden_or_backup_file("..hidden")); + assert_se(!hidden_or_backup_file("hidden.")); + + assert_se(hidden_or_backup_file("backup~")); + assert_se(hidden_or_backup_file(".backup~")); + + assert_se(hidden_or_backup_file("lost+found")); + assert_se(hidden_or_backup_file("aquota.user")); + assert_se(hidden_or_backup_file("aquota.group")); + + assert_se(hidden_or_backup_file("test.rpmnew")); + assert_se(hidden_or_backup_file("test.dpkg-old")); + assert_se(hidden_or_backup_file("test.dpkg-remove")); + assert_se(hidden_or_backup_file("test.swp")); + + assert_se(!hidden_or_backup_file("test.rpmnew.")); + assert_se(!hidden_or_backup_file("test.dpkg-old.foo")); +} + +static void test_systemd_installation_has_version(const char *path) { + int r; + const unsigned versions[] = {0, 231, atoi(PACKAGE_VERSION), 999}; + unsigned i; + + for (i = 0; i < ELEMENTSOF(versions); i++) { + r = systemd_installation_has_version(path, versions[i]); + assert_se(r >= 0); + log_info("%s has systemd >= %u: %s", + path ?: "Current installation", versions[i], yes_no(r)); + } +} + int main(int argc, char **argv) { + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + log_open(); + test_path(); - test_find_binary(argv[0], true); - test_find_binary(argv[0], false); + test_find_binary(argv[0]); test_prefixes(); test_path_join(); test_fsck_exists(); @@ -460,6 +539,11 @@ int main(int argc, char **argv) { test_path_startswith(); test_prefix_root(); test_path_is_mount_point(); + test_file_in_same_dir(); + test_filename_is_valid(); + test_hidden_or_backup_file(); + + test_systemd_installation_has_version(argv[1]); /* NULL is OK */ return 0; } diff --git a/src/test/test-path.c b/src/test/test-path.c index 5d190378f1..4d3f0e9948 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -17,16 +17,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <stdbool.h> +#include <stdio.h> -#include "unit.h" -#include "manager.h" -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fs-util.h" #include "macro.h" -#include "strv.h" +#include "manager.h" #include "mkdir.h" #include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "test-helper.h" +#include "tests.h" +#include "unit.h" +#include "util.h" typedef void (*test_function_t)(Manager *m); @@ -39,9 +45,9 @@ static int setup_test(Manager **m) { assert_se(m); - r = manager_new(MANAGER_USER, true, &tmp); - if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) { - printf("Skipping test: manager_new: %s", strerror(-r)); + r = manager_new(UNIT_FILE_USER, true, &tmp); + if (MANAGER_SKIP_TEST(r)) { + log_notice_errno(r, "Skipping test: manager_new: %m"); return -EXIT_TEST_SKIP; } assert_se(r >= 0); @@ -88,7 +94,7 @@ static void check_stop_unlink(Manager *m, Unit *unit, const char *test_path, con ts = now(CLOCK_MONOTONIC); /* We process events until the service related to the path has been successfully started */ - while(service->result != SERVICE_SUCCESS || service->state != SERVICE_START) { + while (service->result != SERVICE_SUCCESS || service->state != SERVICE_START) { usec_t n; int r; @@ -238,7 +244,7 @@ static void test_path_makedirectory_directorymode(Manager *m) { } int main(int argc, char *argv[]) { - test_function_t tests[] = { + static const test_function_t tests[] = { test_path_exists, test_path_existsglob, test_path_changed, @@ -248,13 +254,16 @@ int main(int argc, char *argv[]) { test_path_makedirectory_directorymode, NULL, }; - test_function_t *test = NULL; + + _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; + const test_function_t *test = NULL; Manager *m = NULL; log_parse_environment(); log_open(); - assert_se(set_unit_path(TEST_DIR) >= 0); + assert_se(runtime_dir = setup_fake_runtime_dir()); + assert_se(set_unit_path(TEST_DIR "/test-path/") >= 0); for (test = tests; test && *test; test++) { int r; diff --git a/src/test/test-prioq.c b/src/test/test-prioq.c index dfedc9b8dc..d81880a655 100644 --- a/src/test/test-prioq.c +++ b/src/test/test-prioq.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,10 +19,11 @@ #include <stdlib.h> -#include "util.h" -#include "set.h" +#include "alloc-util.h" #include "prioq.h" +#include "set.h" #include "siphash24.h" +#include "util.h" #define SET_SIZE 1024*4 @@ -89,13 +88,10 @@ static int test_compare(const void *a, const void *b) { return 0; } -static unsigned long test_hash(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) { +static void test_hash(const void *a, struct siphash *state) { const struct test *x = a; - uint64_t u; - - siphash24((uint8_t*) &u, &x->value, sizeof(x->value), hash_key); - return (unsigned long) u; + siphash24_compress(&x->value, sizeof(x->value), state); } static const struct hash_ops test_hash_ops = { diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c new file mode 100644 index 0000000000..80ad5ed98b --- /dev/null +++ b/src/test/test-proc-cmdline.c @@ -0,0 +1,63 @@ +/*** + This file is part of systemd. + + Copyright 2010 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 "alloc-util.h" +#include "log.h" +#include "macro.h" +#include "proc-cmdline.h" +#include "special.h" +#include "string-util.h" +#include "util.h" + +static int parse_item(const char *key, const char *value) { + assert_se(key); + + log_info("kernel cmdline option <%s> = <%s>", key, strna(value)); + return 0; +} + +static void test_parse_proc_cmdline(void) { + assert_se(parse_proc_cmdline(parse_item) >= 0); +} + +static void test_runlevel_to_target(void) { + in_initrd_force(false); + assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); + assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET)); + assert_se(streq_ptr(runlevel_to_target("rd.rescue"), NULL)); + + in_initrd_force(true); + assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); + assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("3"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.rescue"), SPECIAL_RESCUE_TARGET)); +} + +int main(void) { + log_parse_environment(); + log_open(); + + test_parse_proc_cmdline(); + test_runlevel_to_target(); + + return 0; +} diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index e4e2efecd5..9ada46b1e9 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -18,78 +18,88 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> +#include <sched.h> +#include <sys/mount.h> +#include <sys/personality.h> +#include <sys/prctl.h> #include <sys/stat.h> +#include <sys/types.h> #include <sys/wait.h> #include <unistd.h> +#ifdef HAVE_VALGRIND_VALGRIND_H +#include <valgrind/valgrind.h> +#endif -#include "process-util.h" +#include "alloc-util.h" +#include "architecture.h" +#include "fd-util.h" #include "log.h" -#include "util.h" #include "macro.h" -#include "virt.h" +#include "parse-util.h" +#include "process-util.h" +#include "stdio-util.h" +#include "string-util.h" #include "terminal-util.h" +#include "test-helper.h" +#include "util.h" +#include "virt.h" -static void test_get_process_comm(void) { +static void test_get_process_comm(pid_t pid) { struct stat st; - _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL, *cwd = NULL, *root = NULL; + _cleanup_free_ char *a = NULL, *c = NULL, *d = NULL, *f = NULL, *i = NULL; _cleanup_free_ char *env = NULL; + char path[strlen("/proc//comm") + DECIMAL_STR_MAX(pid_t)]; pid_t e; uid_t u; gid_t g; dev_t h; int r; - pid_t me; - - if (stat("/proc/1/comm", &st) == 0) { - assert_se(get_process_comm(1, &a) >= 0); - log_info("pid1 comm: '%s'", a); - } else - log_warning("/proc/1/comm does not exist."); - - assert_se(get_process_cmdline(1, 0, true, &c) >= 0); - log_info("pid1 cmdline: '%s'", c); - assert_se(get_process_cmdline(1, 8, false, &d) >= 0); - log_info("pid1 cmdline truncated: '%s'", d); + xsprintf(path, "/proc/"PID_FMT"/comm", pid); - assert_se(get_parent_of_pid(1, &e) >= 0); - log_info("pid1 ppid: "PID_FMT, e); - assert_se(e == 0); + if (stat(path, &st) == 0) { + assert_se(get_process_comm(pid, &a) >= 0); + log_info("PID"PID_FMT" comm: '%s'", pid, a); + } else + log_warning("%s not exist.", path); - assert_se(is_kernel_thread(1) == 0); + assert_se(get_process_cmdline(pid, 0, true, &c) >= 0); + log_info("PID"PID_FMT" cmdline: '%s'", pid, c); - r = get_process_exe(1, &f); - assert_se(r >= 0 || r == -EACCES); - log_info("pid1 exe: '%s'", strna(f)); + assert_se(get_process_cmdline(pid, 8, false, &d) >= 0); + log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d); - assert_se(get_process_uid(1, &u) == 0); - log_info("pid1 uid: "UID_FMT, u); - assert_se(u == 0); + free(d); + assert_se(get_process_cmdline(pid, 1, false, &d) >= 0); + log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d); - assert_se(get_process_gid(1, &g) == 0); - log_info("pid1 gid: "GID_FMT, g); - assert_se(g == 0); + assert_se(get_process_ppid(pid, &e) >= 0); + log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e); + assert_se(pid == 1 ? e == 0 : e > 0); - me = getpid(); + assert_se(is_kernel_thread(pid) == 0 || pid != 1); - r = get_process_cwd(me, &cwd); + r = get_process_exe(pid, &f); assert_se(r >= 0 || r == -EACCES); - log_info("pid1 cwd: '%s'", cwd); + log_info("PID"PID_FMT" exe: '%s'", pid, strna(f)); - r = get_process_root(me, &root); - assert_se(r >= 0 || r == -EACCES); - log_info("pid1 root: '%s'", root); + assert_se(get_process_uid(pid, &u) == 0); + log_info("PID"PID_FMT" UID: "UID_FMT, pid, u); + assert_se(u == 0 || pid != 1); - r = get_process_environ(me, &env); + assert_se(get_process_gid(pid, &g) == 0); + log_info("PID"PID_FMT" GID: "GID_FMT, pid, g); + assert_se(g == 0 || pid != 1); + + r = get_process_environ(pid, &env); assert_se(r >= 0 || r == -EACCES); - log_info("self strlen(environ): '%zu'", strlen(env)); + log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno); - if (!detect_container(NULL)) - assert_se(get_ctty_devnr(1, &h) == -ENXIO); + if (!detect_container()) + assert_se(get_ctty_devnr(pid, &h) == -ENXIO || pid != 1); - getenv_for_pid(1, "PATH", &i); - log_info("pid1 $PATH: '%s'", strna(i)); + getenv_for_pid(pid, "PATH", &i); + log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i)); } static void test_pid_is_unwaited(void) { @@ -126,13 +136,236 @@ static void test_pid_is_alive(void) { assert_se(!pid_is_alive(-1)); } +static void test_personality(void) { + + assert_se(personality_to_string(PER_LINUX)); + assert_se(!personality_to_string(PERSONALITY_INVALID)); + + assert_se(streq(personality_to_string(PER_LINUX), architecture_to_string(native_architecture()))); + + assert_se(personality_from_string(personality_to_string(PER_LINUX)) == PER_LINUX); + assert_se(personality_from_string(architecture_to_string(native_architecture())) == PER_LINUX); + +#ifdef __x86_64__ + assert_se(streq_ptr(personality_to_string(PER_LINUX), "x86-64")); + assert_se(streq_ptr(personality_to_string(PER_LINUX32), "x86")); + + assert_se(personality_from_string("x86-64") == PER_LINUX); + assert_se(personality_from_string("x86") == PER_LINUX32); + assert_se(personality_from_string("ia64") == PERSONALITY_INVALID); + assert_se(personality_from_string(NULL) == PERSONALITY_INVALID); + + assert_se(personality_from_string(personality_to_string(PER_LINUX32)) == PER_LINUX32); +#endif +} + +static void test_get_process_cmdline_harder(void) { + char path[] = "/tmp/test-cmdlineXXXXXX"; + _cleanup_close_ int fd = -1; + _cleanup_free_ char *line = NULL; + pid_t pid; + + if (geteuid() != 0) + return; + +#ifdef HAVE_VALGRIND_VALGRIND_H + /* valgrind patches open(/proc//cmdline) + * so, test_get_process_cmdline_harder fails always + * See https://github.com/systemd/systemd/pull/3555#issuecomment-226564908 */ + if (RUNNING_ON_VALGRIND) + return; +#endif + + pid = fork(); + if (pid > 0) { + siginfo_t si; + + (void) wait_for_terminate(pid, &si); + + assert_se(si.si_code == CLD_EXITED); + assert_se(si.si_status == 0); + + return; + } + + assert_se(pid == 0); + assert_se(unshare(CLONE_NEWNS) >= 0); + + fd = mkostemp(path, O_CLOEXEC); + assert_se(fd >= 0); + assert_se(mount(path, "/proc/self/cmdline", "bind", MS_BIND, NULL) >= 0); + assert_se(unlink(path) >= 0); + + assert_se(prctl(PR_SET_NAME, "testa") >= 0); + + assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "[testa]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 1, true, &line) >= 0); + assert_se(streq(line, "")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 2, true, &line) >= 0); + assert_se(streq(line, "[")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 3, true, &line) >= 0); + assert_se(streq(line, "[.")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 4, true, &line) >= 0); + assert_se(streq(line, "[..")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 5, true, &line) >= 0); + assert_se(streq(line, "[...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 6, true, &line) >= 0); + assert_se(streq(line, "[...]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 7, true, &line) >= 0); + assert_se(streq(line, "[t...]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 8, true, &line) >= 0); + assert_se(streq(line, "[testa]")); + line = mfree(line); + + assert_se(write(fd, "\0\0\0\0\0\0\0\0\0", 10) == 10); + + assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "[testa]")); + line = mfree(line); + + assert_se(write(fd, "foo\0bar\0\0\0\0\0", 10) == 10); + + assert_se(get_process_cmdline(getpid(), 0, false, &line) >= 0); + assert_se(streq(line, "foo bar")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "foo bar")); + line = mfree(line); + + assert_se(write(fd, "quux", 4) == 4); + assert_se(get_process_cmdline(getpid(), 0, false, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 1, true, &line) >= 0); + assert_se(streq(line, "")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 2, true, &line) >= 0); + assert_se(streq(line, ".")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 3, true, &line) >= 0); + assert_se(streq(line, "..")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 4, true, &line) >= 0); + assert_se(streq(line, "...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 5, true, &line) >= 0); + assert_se(streq(line, "f...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 6, true, &line) >= 0); + assert_se(streq(line, "fo...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 7, true, &line) >= 0); + assert_se(streq(line, "foo...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 8, true, &line) >= 0); + assert_se(streq(line, "foo...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 9, true, &line) >= 0); + assert_se(streq(line, "foo b...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 10, true, &line) >= 0); + assert_se(streq(line, "foo ba...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 11, true, &line) >= 0); + assert_se(streq(line, "foo bar...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 12, true, &line) >= 0); + assert_se(streq(line, "foo bar...")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 13, true, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 14, true, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 1000, true, &line) >= 0); + assert_se(streq(line, "foo bar quux")); + line = mfree(line); + + assert_se(ftruncate(fd, 0) >= 0); + assert_se(prctl(PR_SET_NAME, "aaaa bbbb cccc") >= 0); + + assert_se(get_process_cmdline(getpid(), 0, false, &line) == -ENOENT); + + assert_se(get_process_cmdline(getpid(), 0, true, &line) >= 0); + assert_se(streq(line, "[aaaa bbbb cccc]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 10, true, &line) >= 0); + assert_se(streq(line, "[aaaa...]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 11, true, &line) >= 0); + assert_se(streq(line, "[aaaa...]")); + line = mfree(line); + + assert_se(get_process_cmdline(getpid(), 12, true, &line) >= 0); + assert_se(streq(line, "[aaaa b...]")); + line = mfree(line); + + safe_close(fd); + _exit(0); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - test_get_process_comm(); + if (argc > 1) { + pid_t pid = 0; + + (void) parse_pid(argv[1], &pid); + test_get_process_comm(pid); + } else { + TEST_REQ_RUNNING_SYSTEMD(test_get_process_comm(1)); + test_get_process_comm(getpid()); + } + test_pid_is_unwaited(); test_pid_is_alive(); + test_personality(); + test_get_process_cmdline_harder(); return 0; } diff --git a/src/test/test-pty.c b/src/test/test-pty.c deleted file mode 100644 index fbab3d4ebe..0000000000 --- a/src/test/test-pty.c +++ /dev/null @@ -1,142 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 David Herrmann <dh.herrmann@gmail.com> - - 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 <errno.h> -#include <locale.h> -#include <string.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "pty.h" -#include "util.h" -#include "signal-util.h" - -static const char sndmsg[] = "message\n"; -static const char rcvmsg[] = "message\r\n"; -static char rcvbuf[128]; -static size_t rcvsiz = 0; -static sd_event *event; - -static void run_child(Pty *pty) { - ssize_t r, l; - char buf[512]; - - r = read(0, buf, sizeof(buf)); - assert_se((size_t)r == strlen(sndmsg)); - assert_se(!strncmp(buf, sndmsg, r)); - - l = write(1, buf, r); - assert_se(l == r); -} - -static int pty_fn(Pty *pty, void *userdata, unsigned int ev, const void *ptr, size_t size) { - switch (ev) { - case PTY_DATA: - assert_se(rcvsiz < strlen(rcvmsg) * 2); - assert_se(rcvsiz + size < sizeof(rcvbuf)); - - memcpy(&rcvbuf[rcvsiz], ptr, size); - rcvsiz += size; - - if (rcvsiz >= strlen(rcvmsg) * 2) { - assert_se(rcvsiz == strlen(rcvmsg) * 2); - assert_se(!memcmp(rcvbuf, rcvmsg, strlen(rcvmsg))); - assert_se(!memcmp(&rcvbuf[strlen(rcvmsg)], rcvmsg, strlen(rcvmsg))); - } - - break; - case PTY_HUP: - /* This is guaranteed to appear _after_ the input queues are - * drained! */ - assert_se(rcvsiz == strlen(rcvmsg) * 2); - break; - case PTY_CHILD: - /* this may appear at any time */ - break; - default: - assert_se(0); - break; - } - - /* if we got HUP _and_ CHILD, exit */ - if (pty_get_fd(pty) < 0 && pty_get_child(pty) < 0) - sd_event_exit(event, 0); - - return 0; -} - -static void run_parent(Pty *pty) { - int r; - - /* write message to pty, ECHO mode guarantees that we get it back - * twice: once via ECHO, once from the run_child() fn */ - assert_se(pty_write(pty, sndmsg, strlen(sndmsg)) >= 0); - - r = sd_event_loop(event); - assert_se(r >= 0); -} - -static void test_pty(void) { - pid_t pid; - Pty *pty = NULL; - - rcvsiz = 0; - zero(rcvbuf); - - assert_se(sd_event_default(&event) >= 0); - - pid = pty_fork(&pty, event, pty_fn, NULL, 80, 25); - assert_se(pid >= 0); - - if (pid == 0) { - /* child */ - run_child(pty); - exit(0); - } - - /* parent */ - run_parent(pty); - - /* Make sure the PTY recycled the child; yeah, this is racy if the - * PID was already reused; but that seems fine for a test. */ - assert_se(waitpid(pid, NULL, WNOHANG) < 0 && errno == ECHILD); - - pty_unref(pty); - sd_event_unref(event); -} - -int main(int argc, char *argv[]) { - unsigned int i; - - log_parse_environment(); - log_open(); - - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0); - - /* Oh, there're ugly races in the TTY layer regarding HUP vs IN. Turns - * out they appear only 10% of the time. I fixed all of them and - * don't see them, anymore. But let's be safe and run this 1000 times - * so we catch any new ones, in case they appear again. */ - for (i = 0; i < 1000; ++i) - test_pty(); - - return 0; -} diff --git a/src/test/test-ratelimit.c b/src/test/test-ratelimit.c index b7f6dfe246..990b834c79 100644 --- a/src/test/test-ratelimit.c +++ b/src/test/test-ratelimit.c @@ -19,27 +19,24 @@ #include <unistd.h> +#include "macro.h" #include "ratelimit.h" #include "time-util.h" -#include "macro.h" static void test_ratelimit_test(void) { int i; RATELIMIT_DEFINE(ratelimit, 1 * USEC_PER_SEC, 10); - for (i = 0; i < 10; i++) { + for (i = 0; i < 10; i++) assert_se(ratelimit_test(&ratelimit)); - } assert_se(!ratelimit_test(&ratelimit)); sleep(1); - for (i = 0; i < 10; i++) { + for (i = 0; i < 10; i++) assert_se(ratelimit_test(&ratelimit)); - } RATELIMIT_INIT(ratelimit, 0, 10); - for (i = 0; i < 10000; i++) { + for (i = 0; i < 10000; i++) assert_se(ratelimit_test(&ratelimit)); - } } int main(int argc, char *argv[]) { diff --git a/src/test/test-replace-var.c b/src/test/test-replace-var.c index b1d42d77fd..297effce79 100644 --- a/src/test/test-replace-var.c +++ b/src/test/test-replace-var.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,9 +19,10 @@ #include <string.h> -#include "util.h" #include "macro.h" #include "replace-var.h" +#include "string-util.h" +#include "util.h" static char *lookup(const char *variable, void *userdata) { return strjoin("<<<", variable, ">>>", NULL); diff --git a/src/test/test-ring.c b/src/test/test-ring.c deleted file mode 100644 index cb8a5d4e9e..0000000000 --- a/src/test/test-ring.c +++ /dev/null @@ -1,130 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 David Herrmann <dh.herrmann@gmail.com> - - 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 <string.h> - -#include "def.h" -#include "ring.h" - -static void test_ring(void) { - static const char buf[8192]; - Ring r; - size_t l; - struct iovec vec[2]; - int s; - - zero(r); - - l = ring_peek(&r, vec); - assert_se(l == 0); - - s = ring_push(&r, buf, 2048); - assert_se(!s); - assert_se(ring_get_size(&r) == 2048); - - l = ring_peek(&r, vec); - assert_se(l == 1); - assert_se(vec[0].iov_len == 2048); - assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len)); - assert_se(ring_get_size(&r) == 2048); - - ring_pull(&r, 2048); - assert_se(ring_get_size(&r) == 0); - - l = ring_peek(&r, vec); - assert_se(l == 0); - assert_se(ring_get_size(&r) == 0); - - s = ring_push(&r, buf, 2048); - assert_se(!s); - assert_se(ring_get_size(&r) == 2048); - - l = ring_peek(&r, vec); - assert_se(l == 1); - assert_se(vec[0].iov_len == 2048); - assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len)); - assert_se(ring_get_size(&r) == 2048); - - s = ring_push(&r, buf, 1); - assert_se(!s); - assert_se(ring_get_size(&r) == 2049); - - l = ring_peek(&r, vec); - assert_se(l == 2); - assert_se(vec[0].iov_len == 2048); - assert_se(vec[1].iov_len == 1); - assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len)); - assert_se(!memcmp(vec[1].iov_base, buf, vec[1].iov_len)); - assert_se(ring_get_size(&r) == 2049); - - ring_pull(&r, 2048); - assert_se(ring_get_size(&r) == 1); - - l = ring_peek(&r, vec); - assert_se(l == 1); - assert_se(vec[0].iov_len == 1); - assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len)); - assert_se(ring_get_size(&r) == 1); - - ring_pull(&r, 1); - assert_se(ring_get_size(&r) == 0); - - s = ring_push(&r, buf, 2048); - assert_se(!s); - assert_se(ring_get_size(&r) == 2048); - - s = ring_push(&r, buf, 2049); - assert_se(!s); - assert_se(ring_get_size(&r) == 4097); - - l = ring_peek(&r, vec); - assert_se(l == 1); - assert_se(vec[0].iov_len == 4097); - assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len)); - assert_se(ring_get_size(&r) == 4097); - - ring_pull(&r, 1); - assert_se(ring_get_size(&r) == 4096); - - s = ring_push(&r, buf, 4096); - assert_se(!s); - assert_se(ring_get_size(&r) == 8192); - - l = ring_peek(&r, vec); - assert_se(l == 2); - assert_se(vec[0].iov_len == 8191); - assert_se(vec[1].iov_len == 1); - assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len)); - assert_se(!memcmp(vec[1].iov_base, buf, vec[1].iov_len)); - assert_se(ring_get_size(&r) == 8192); - - ring_clear(&r); - assert_se(ring_get_size(&r) == 0); -} - -int main(int argc, char *argv[]) { - log_parse_environment(); - log_open(); - - test_ring(); - - return 0; -} diff --git a/src/test/test-rlimit-util.c b/src/test/test-rlimit-util.c new file mode 100644 index 0000000000..62afd2de5e --- /dev/null +++ b/src/test/test-rlimit-util.c @@ -0,0 +1,116 @@ +/*** + This file is part of systemd + + 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/resource.h> + +#include "alloc-util.h" +#include "capability-util.h" +#include "macro.h" +#include "rlimit-util.h" +#include "string-util.h" +#include "util.h" + +static void test_rlimit_parse_format(int resource, const char *string, rlim_t soft, rlim_t hard, int ret, const char *formatted) { + _cleanup_free_ char *f = NULL; + struct rlimit rl = { + .rlim_cur = 4711, + .rlim_max = 4712, + }, rl2 = { + .rlim_cur = 4713, + .rlim_max = 4714 + }; + + assert_se(rlimit_parse(resource, string, &rl) == ret); + if (ret < 0) + return; + + assert_se(rl.rlim_cur == soft); + assert_se(rl.rlim_max == hard); + + assert_se(rlimit_format(&rl, &f) >= 0); + assert_se(streq(formatted, f)); + + assert_se(rlimit_parse(resource, formatted, &rl2) >= 0); + assert_se(memcmp(&rl, &rl2, sizeof(struct rlimit)) == 0); +} + +int main(int argc, char *argv[]) { + struct rlimit old, new, high; + struct rlimit err = { + .rlim_cur = 10, + .rlim_max = 5, + }; + + log_parse_environment(); + log_open(); + + assert_se(drop_capability(CAP_SYS_RESOURCE) == 0); + + assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0); + new.rlim_cur = MIN(5U, old.rlim_max); + new.rlim_max = old.rlim_max; + assert_se(setrlimit(RLIMIT_NOFILE, &new) >= 0); + + assert_se(rlimit_from_string("LimitNOFILE") == RLIMIT_NOFILE); + assert_se(rlimit_from_string("DefaultLimitNOFILE") == -1); + + assert_se(streq_ptr(rlimit_to_string(RLIMIT_NOFILE), "LimitNOFILE")); + assert_se(rlimit_to_string(-1) == NULL); + + assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0); + assert_se(setrlimit_closest(RLIMIT_NOFILE, &old) == 0); + assert_se(getrlimit(RLIMIT_NOFILE, &new) == 0); + assert_se(old.rlim_cur == new.rlim_cur); + assert_se(old.rlim_max == new.rlim_max); + + assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0); + high = RLIMIT_MAKE_CONST(old.rlim_max == RLIM_INFINITY ? old.rlim_max : old.rlim_max + 1); + assert_se(setrlimit_closest(RLIMIT_NOFILE, &high) == 0); + assert_se(getrlimit(RLIMIT_NOFILE, &new) == 0); + assert_se(new.rlim_max == old.rlim_max); + assert_se(new.rlim_cur == new.rlim_max); + + assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0); + assert_se(setrlimit_closest(RLIMIT_NOFILE, &err) == -EINVAL); + assert_se(getrlimit(RLIMIT_NOFILE, &new) == 0); + assert_se(old.rlim_cur == new.rlim_cur); + assert_se(old.rlim_max == new.rlim_max); + + test_rlimit_parse_format(RLIMIT_NOFILE, "4:5", 4, 5, 0, "4:5"); + test_rlimit_parse_format(RLIMIT_NOFILE, "6", 6, 6, 0, "6"); + test_rlimit_parse_format(RLIMIT_NOFILE, "infinity", RLIM_INFINITY, RLIM_INFINITY, 0, "infinity"); + test_rlimit_parse_format(RLIMIT_NOFILE, "infinity:infinity", RLIM_INFINITY, RLIM_INFINITY, 0, "infinity"); + test_rlimit_parse_format(RLIMIT_NOFILE, "8:infinity", 8, RLIM_INFINITY, 0, "8:infinity"); + test_rlimit_parse_format(RLIMIT_CPU, "25min:13h", (25*USEC_PER_MINUTE) / USEC_PER_SEC, (13*USEC_PER_HOUR) / USEC_PER_SEC, 0, "1500:46800"); + test_rlimit_parse_format(RLIMIT_NOFILE, "", 0, 0, -EINVAL, NULL); + test_rlimit_parse_format(RLIMIT_NOFILE, "5:4", 0, 0, -EILSEQ, NULL); + test_rlimit_parse_format(RLIMIT_NOFILE, "5:4:3", 0, 0, -EINVAL, NULL); + test_rlimit_parse_format(RLIMIT_NICE, "20", 20, 20, 0, "20"); + test_rlimit_parse_format(RLIMIT_NICE, "40", 40, 40, 0, "40"); + test_rlimit_parse_format(RLIMIT_NICE, "41", 41, 41, -ERANGE, "41"); + test_rlimit_parse_format(RLIMIT_NICE, "0", 0, 0, 0, "0"); + test_rlimit_parse_format(RLIMIT_NICE, "-7", 27, 27, 0, "27"); + test_rlimit_parse_format(RLIMIT_NICE, "-20", 40, 40, 0, "40"); + test_rlimit_parse_format(RLIMIT_NICE, "-21", 41, 41, -ERANGE, "41"); + test_rlimit_parse_format(RLIMIT_NICE, "-0", 20, 20, 0, "20"); + test_rlimit_parse_format(RLIMIT_NICE, "+7", 13, 13, 0, "13"); + test_rlimit_parse_format(RLIMIT_NICE, "+19", 1, 1, 0, "1"); + test_rlimit_parse_format(RLIMIT_NICE, "+20", 0, 0, -ERANGE, "0"); + test_rlimit_parse_format(RLIMIT_NICE, "+0", 20, 20, 0, "20"); + + return 0; +} diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c index f915539e00..7b37910c33 100644 --- a/src/test/test-sched-prio.c +++ b/src/test/test-sched-prio.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,10 +19,14 @@ #include <sched.h> -#include "manager.h" #include "macro.h" +#include "manager.h" +#include "rm-rf.h" +#include "test-helper.h" +#include "tests.h" int main(int argc, char *argv[]) { + _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; Manager *m = NULL; Unit *idle_ok, *idle_bad, *rr_ok, *rr_bad, *rr_sched; Service *ser; @@ -32,11 +34,13 @@ int main(int argc, char *argv[]) { FDSet *fdset = NULL; int r; + assert_se(runtime_dir = setup_fake_runtime_dir()); + /* prepare the test */ assert_se(set_unit_path(TEST_DIR) >= 0); - r = manager_new(MANAGER_USER, true, &m); - if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) { - printf("Skipping test: manager_new: %s", strerror(-r)); + r = manager_new(UNIT_FILE_USER, true, &m); + if (MANAGER_SKIP_TEST(r)) { + log_notice_errno(r, "Skipping test: manager_new: %m"); return EXIT_TEST_SKIP; } assert_se(r >= 0); diff --git a/src/test/test-selinux.c b/src/test/test-selinux.c new file mode 100644 index 0000000000..7545ad3764 --- /dev/null +++ b/src/test/test-selinux.c @@ -0,0 +1,122 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 "alloc-util.h" +#include "fd-util.h" +#include "log.h" +#include "selinux-util.h" +#include "string-util.h" +#include "time-util.h" +#include "util.h" + +static void test_testing(void) { + bool b; + + log_info("============ %s ==========", __func__); + + b = mac_selinux_use(); + log_info("mac_selinux_use → %s", yes_no(b)); + + b = mac_selinux_have(); + log_info("mac_selinux_have → %s", yes_no(b)); + + mac_selinux_retest(); + + b = mac_selinux_use(); + log_info("mac_selinux_use → %s", yes_no(b)); + + b = mac_selinux_have(); + log_info("mac_selinux_have → %s", yes_no(b)); +} + +static void test_loading(void) { + usec_t n1, n2; + int r; + + log_info("============ %s ==========", __func__); + + n1 = now(CLOCK_MONOTONIC); + r = mac_selinux_init(); + n2 = now(CLOCK_MONOTONIC); + log_info_errno(r, "mac_selinux_init → %d (%m) %.2fs", r, (n2 - n1)/1e6); +} + +static void test_cleanup(void) { + usec_t n1, n2; + + log_info("============ %s ==========", __func__); + + n1 = now(CLOCK_MONOTONIC); + mac_selinux_finish(); + n2 = now(CLOCK_MONOTONIC); + log_info("mac_selinux_finish → %.2fs", (n2 - n1)/1e6); +} + +static void test_misc(const char* fname) { + _cleanup_(mac_selinux_freep) char *label = NULL, *label2 = NULL, *label3 = NULL; + int r; + _cleanup_close_ int fd = -1; + + log_info("============ %s ==========", __func__); + + r = mac_selinux_get_our_label(&label); + log_info_errno(r, "mac_selinux_get_our_label → %d (%m), \"%s\"", + r, strnull(label)); + + r = mac_selinux_get_create_label_from_exe(fname, &label2); + log_info_errno(r, "mac_selinux_create_label_from_exe → %d (%m), \"%s\"", + r, strnull(label2)); + + fd = socket(AF_INET, SOCK_DGRAM, 0); + assert_se(fd >= 0); + + r = mac_selinux_get_child_mls_label(fd, fname, label2, &label3); + log_info_errno(r, "mac_selinux_get_child_mls_label → %d (%m), \"%s\"", + r, strnull(label3)); +} + +static void test_create_file_prepare(const char* fname) { + int r; + + log_info("============ %s ==========", __func__); + + r = mac_selinux_create_file_prepare(fname, S_IRWXU); + log_info_errno(r, "mac_selinux_create_file_prepare → %d (%m)", r); + + mac_selinux_create_file_clear(); +} + +int main(int argc, char **argv) { + const char *path = SYSTEMD_BINARY_PATH; + if (argc >= 2) + path = argv[1]; + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + + test_testing(); + test_loading(); + test_misc(path); + test_create_file_prepare(path); + test_cleanup(); + + return 0; +} diff --git a/src/test/test-sigbus.c b/src/test/test-sigbus.c index f5bae65bef..02b8e24308 100644 --- a/src/test/test-sigbus.c +++ b/src/test/test-sigbus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,8 +19,9 @@ #include <sys/mman.h> -#include "util.h" +#include "fd-util.h" #include "sigbus.h" +#include "util.h" int main(int argc, char *argv[]) { _cleanup_close_ int fd = -1; @@ -30,6 +29,9 @@ int main(int argc, char *argv[]) { void *addr = NULL; uint8_t *p; +#ifdef __SANITIZE_ADDRESS__ + return EXIT_TEST_SKIP; +#endif sigbus_install(); assert_se(sigbus_pop(&addr) == 0); diff --git a/src/test/test-signal-util.c b/src/test/test-signal-util.c new file mode 100644 index 0000000000..671eb869cb --- /dev/null +++ b/src/test/test-signal-util.c @@ -0,0 +1,67 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 <signal.h> +#include <unistd.h> + +#include "macro.h" +#include "signal-util.h" + +static void test_block_signals(void) { + sigset_t ss; + + assert_se(sigprocmask(0, NULL, &ss) >= 0); + + assert_se(sigismember(&ss, SIGUSR1) == 0); + assert_se(sigismember(&ss, SIGALRM) == 0); + assert_se(sigismember(&ss, SIGVTALRM) == 0); + + { + BLOCK_SIGNALS(SIGUSR1, SIGVTALRM); + + assert_se(sigprocmask(0, NULL, &ss) >= 0); + assert_se(sigismember(&ss, SIGUSR1) == 1); + assert_se(sigismember(&ss, SIGALRM) == 0); + assert_se(sigismember(&ss, SIGVTALRM) == 1); + + } + + assert_se(sigprocmask(0, NULL, &ss) >= 0); + assert_se(sigismember(&ss, SIGUSR1) == 0); + assert_se(sigismember(&ss, SIGALRM) == 0); + assert_se(sigismember(&ss, SIGVTALRM) == 0); +} + +static void test_ignore_signals(void) { + assert_se(ignore_signals(SIGINT, -1) >= 0); + assert_se(kill(getpid(), SIGINT) >= 0); + assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); + assert_se(kill(getpid(), SIGUSR1) >= 0); + assert_se(kill(getpid(), SIGUSR2) >= 0); + assert_se(kill(getpid(), SIGTERM) >= 0); + assert_se(kill(getpid(), SIGPIPE) >= 0); + assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); +} + +int main(int argc, char *argv[]) { + test_block_signals(); + test_ignore_signals(); + + return 0; +} diff --git a/src/test/test-siphash24.c b/src/test/test-siphash24.c new file mode 100644 index 0000000000..b74b7ad2dd --- /dev/null +++ b/src/test/test-siphash24.c @@ -0,0 +1,124 @@ +/*** + This file is part of systemd. + + Copyright 2015 Tom Gundersen + + 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 "siphash24.h" +#include "util.h" + +#define ITERATIONS 10000000ULL + +static void do_test(const uint8_t *in, size_t len, const uint8_t *key) { + struct siphash state = {}; + uint64_t out; + unsigned i, j; + + out = siphash24(in, len, key); + assert_se(out == 0xa129ca6149be45e5); + + /* verify the internal state as given in the above paper */ + siphash24_init(&state, key); + assert_se(state.v0 == 0x7469686173716475); + assert_se(state.v1 == 0x6b617f6d656e6665); + assert_se(state.v2 == 0x6b7f62616d677361); + assert_se(state.v3 == 0x7b6b696e727e6c7b); + siphash24_compress(in, len, &state); + assert_se(state.v0 == 0x4a017198de0a59e0); + assert_se(state.v1 == 0x0d52f6f62a4f59a4); + assert_se(state.v2 == 0x634cb3577b01fd3d); + assert_se(state.v3 == 0xa5224d6f55c7d9c8); + out = siphash24_finalize(&state); + assert_se(out == 0xa129ca6149be45e5); + assert_se(state.v0 == 0xf6bcd53893fecff1); + assert_se(state.v1 == 0x54b9964c7ea0d937); + assert_se(state.v2 == 0x1b38329c099bb55a); + assert_se(state.v3 == 0x1814bb89ad7be679); + + /* verify that decomposing the input in three chunks gives the + same result */ + for (i = 0; i < len; i++) { + for (j = i; j < len; j++) { + siphash24_init(&state, key); + siphash24_compress(in, i, &state); + siphash24_compress(&in[i], j - i, &state); + siphash24_compress(&in[j], len - j, &state); + out = siphash24_finalize(&state); + assert_se(out == 0xa129ca6149be45e5); + } + } +} + +static void test_short_hashes(void) { + const uint8_t one[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 }; + const uint8_t key[16] = { 0x22, 0x24, 0x41, 0x22, 0x55, 0x77, 0x88, 0x07, + 0x23, 0x09, 0x23, 0x14, 0x0c, 0x33, 0x0e, 0x0f}; + uint8_t two[sizeof one] = {}; + + struct siphash state1 = {}, state2 = {}; + unsigned i, j; + + siphash24_init(&state1, key); + siphash24_init(&state2, key); + + /* hashing 1, 2, 3, 4, 5, ..., 16 bytes, with the byte after the buffer different */ + for (i = 1; i <= sizeof one; i++) { + siphash24_compress(one, i, &state1); + + two[i-1] = one[i-1]; + siphash24_compress(two, i, &state2); + + assert_se(memcmp(&state1, &state2, sizeof state1) == 0); + } + + /* hashing n and 1, n and 2, n and 3, ..., n-1 and 1, n-2 and 2, ... */ + for (i = sizeof one; i > 0; i--) { + zero(two); + + for (j = 1; j <= sizeof one; j++) { + siphash24_compress(one, i, &state1); + siphash24_compress(one, j, &state1); + + siphash24_compress(one, i, &state2); + two[j-1] = one[j-1]; + siphash24_compress(two, j, &state2); + + assert_se(memcmp(&state1, &state2, sizeof state1) == 0); + } + } +} + +/* see https://131002.net/siphash/siphash.pdf, Appendix A */ +int main(int argc, char *argv[]) { + const uint8_t in[15] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e }; + const uint8_t key[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + uint8_t in_buf[20]; + + /* Test with same input but different alignments. */ + memcpy(in_buf, in, sizeof(in)); + do_test(in_buf, sizeof(in), key); + memcpy(in_buf + 1, in, sizeof(in)); + do_test(in_buf + 1, sizeof(in), key); + memcpy(in_buf + 2, in, sizeof(in)); + do_test(in_buf + 2, sizeof(in), key); + memcpy(in_buf + 4, in, sizeof(in)); + do_test(in_buf + 4, sizeof(in), key); + + test_short_hashes(); +} diff --git a/src/test/test-sizeof.c b/src/test/test-sizeof.c new file mode 100644 index 0000000000..8f99a13772 --- /dev/null +++ b/src/test/test-sizeof.c @@ -0,0 +1,53 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 "log.h" +#include "time-util.h" + +/* Print information about various types. Useful when diagnosing + * gcc diagnostics on an unfamiliar architecture. */ + +#pragma GCC diagnostic ignored "-Wtype-limits" + +#define info(t) \ + log_info("%s → %zu bits%s", STRINGIFY(t), \ + sizeof(t)*CHAR_BIT, \ + strstr(STRINGIFY(t), "signed") ? "" : \ + ((t)-1 < (t)0 ? ", signed" : ", unsigned")); + +int main(void) { + info(char); + info(signed char); + info(unsigned char); + info(short unsigned); + info(unsigned); + info(long unsigned); + info(long long unsigned); + + info(float); + info(double); + info(long double); + + info(size_t); + info(ssize_t); + info(time_t); + info(usec_t); + + return 0; +} diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c index 4308ddfb64..97b6f3015d 100644 --- a/src/test/test-sleep.c +++ b/src/test/test-sleep.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,10 +19,10 @@ #include <stdio.h> -#include "util.h" #include "log.h" #include "sleep-config.h" #include "strv.h" +#include "util.h" static void test_sleep(void) { _cleanup_strv_free_ char diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index f257af445a..1f853a7f16 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -17,12 +17,38 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "socket-util.h" +#include "alloc-util.h" +#include "async.h" +#include "fd-util.h" #include "in-addr-util.h" -#include "util.h" -#include "macro.h" #include "log.h" -#include "async.h" +#include "macro.h" +#include "socket-util.h" +#include "string-util.h" +#include "util.h" + +static void test_ifname_valid(void) { + assert(ifname_valid("foo")); + assert(ifname_valid("eth0")); + + assert(!ifname_valid("0")); + assert(!ifname_valid("99")); + assert(ifname_valid("a99")); + assert(ifname_valid("99a")); + + assert(!ifname_valid(NULL)); + assert(!ifname_valid("")); + assert(!ifname_valid(" ")); + assert(!ifname_valid(" foo")); + assert(!ifname_valid("bar\n")); + assert(!ifname_valid(".")); + assert(!ifname_valid("..")); + assert(ifname_valid("foo.bar")); + assert(!ifname_valid("x:y")); + + assert(ifname_valid("xxxxxxxxxxxxxxx")); + assert(!ifname_valid("xxxxxxxxxxxxxxxx")); +} static void test_socket_address_parse(void) { SocketAddress a; @@ -38,28 +64,25 @@ static void test_socket_address_parse(void) { assert_se(socket_address_parse(&a, "65535") >= 0); - if (socket_ipv6_is_supported()) { - assert_se(socket_address_parse(&a, "[::1]") < 0); - assert_se(socket_address_parse(&a, "[::1]8888") < 0); - assert_se(socket_address_parse(&a, "::1") < 0); - assert_se(socket_address_parse(&a, "[::1]:0") < 0); - assert_se(socket_address_parse(&a, "[::1]:65536") < 0); - assert_se(socket_address_parse(&a, "[a:b:1]:8888") < 0); + /* The checks below will pass even if ipv6 is disabled in + * kernel. The underlying glibc's inet_pton() is just a string + * parser and doesn't make any syscalls. */ - assert_se(socket_address_parse(&a, "8888") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_INET6); + assert_se(socket_address_parse(&a, "[::1]") < 0); + assert_se(socket_address_parse(&a, "[::1]8888") < 0); + assert_se(socket_address_parse(&a, "::1") < 0); + assert_se(socket_address_parse(&a, "[::1]:0") < 0); + assert_se(socket_address_parse(&a, "[::1]:65536") < 0); + assert_se(socket_address_parse(&a, "[a:b:1]:8888") < 0); - assert_se(socket_address_parse(&a, "[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_INET6); + assert_se(socket_address_parse(&a, "8888") >= 0); + assert_se(a.sockaddr.sa.sa_family == (socket_ipv6_is_supported() ? AF_INET6 : AF_INET)); - assert_se(socket_address_parse(&a, "[::1]:8888") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_INET6); - } else { - assert_se(socket_address_parse(&a, "[::1]:8888") < 0); + assert_se(socket_address_parse(&a, "[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888") >= 0); + assert_se(a.sockaddr.sa.sa_family == AF_INET6); - assert_se(socket_address_parse(&a, "8888") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_INET); - } + assert_se(socket_address_parse(&a, "[::1]:8888") >= 0); + assert_se(a.sockaddr.sa.sa_family == AF_INET6); assert_se(socket_address_parse(&a, "192.168.1.254:8888") >= 0); assert_se(a.sockaddr.sa.sa_family == AF_INET); @@ -158,6 +181,20 @@ static void test_socket_address_is_netlink(void) { assert_se(!socket_address_is_netlink(&a, "route 1")); } +static void test_in_addr_is_null(void) { + + union in_addr_union i = {}; + + assert_se(in_addr_is_null(AF_INET, &i) == true); + assert_se(in_addr_is_null(AF_INET6, &i) == true); + + i.in.s_addr = 0x1000000; + assert_se(in_addr_is_null(AF_INET, &i) == false); + assert_se(in_addr_is_null(AF_INET6, &i) == false); + + assert_se(in_addr_is_null(-1, &i) == -EAFNOSUPPORT); +} + static void test_in_addr_prefix_intersect_one(unsigned f, const char *a, unsigned apl, const char *b, unsigned bpl, int result) { union in_addr_union ua, ub; @@ -249,6 +286,55 @@ static void test_in_addr_to_string(void) { test_in_addr_to_string_one(AF_INET6, "fe80::"); } +static void test_in_addr_ifindex_to_string_one(int f, const char *a, int ifindex, const char *b) { + _cleanup_free_ char *r = NULL; + union in_addr_union ua, uuaa; + int ff, ifindex2; + + assert_se(in_addr_from_string(f, a, &ua) >= 0); + assert_se(in_addr_ifindex_to_string(f, &ua, ifindex, &r) >= 0); + printf("test_in_addr_ifindex_to_string_one: %s == %s\n", b, r); + assert_se(streq(b, r)); + + assert_se(in_addr_ifindex_from_string_auto(b, &ff, &uuaa, &ifindex2) >= 0); + assert_se(ff == f); + assert_se(in_addr_equal(f, &ua, &uuaa)); + assert_se(ifindex2 == ifindex || ifindex2 == 0); +} + +static void test_in_addr_ifindex_to_string(void) { + test_in_addr_ifindex_to_string_one(AF_INET, "192.168.0.1", 7, "192.168.0.1"); + test_in_addr_ifindex_to_string_one(AF_INET, "10.11.12.13", 9, "10.11.12.13"); + test_in_addr_ifindex_to_string_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 10, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); + test_in_addr_ifindex_to_string_one(AF_INET6, "::1", 11, "::1"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::", 12, "fe80::%12"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::", 0, "fe80::"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::14", 12, "fe80::14%12"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::15", -7, "fe80::15"); + test_in_addr_ifindex_to_string_one(AF_INET6, "fe80::16", LOOPBACK_IFINDEX, "fe80::16%1"); +} + +static void test_in_addr_ifindex_from_string_auto(void) { + int family, ifindex; + union in_addr_union ua; + + /* Most in_addr_ifindex_from_string_auto() invocations have already been tested above, but let's test some more */ + + assert_se(in_addr_ifindex_from_string_auto("fe80::17", &family, &ua, &ifindex) >= 0); + assert_se(family == AF_INET6); + assert_se(ifindex == 0); + + assert_se(in_addr_ifindex_from_string_auto("fe80::18%19", &family, &ua, &ifindex) >= 0); + assert_se(family == AF_INET6); + assert_se(ifindex == 19); + + assert_se(in_addr_ifindex_from_string_auto("fe80::18%lo", &family, &ua, &ifindex) >= 0); + assert_se(family == AF_INET6); + assert_se(ifindex == LOOPBACK_IFINDEX); + + assert_se(in_addr_ifindex_from_string_auto("fe80::19%thisinterfacecantexist", &family, &ua, &ifindex) == -ENODEV); +} + static void *connect_thread(void *arg) { union sockaddr_union *sa = arg; _cleanup_close_ int fd = -1; @@ -267,7 +353,7 @@ static void test_nameinfo_pretty(void) { union sockaddr_union s = { .in.sin_family = AF_INET, .in.sin_port = 0, - .in.sin_addr.s_addr = htonl(INADDR_ANY), + .in.sin_addr.s_addr = htobe32(INADDR_ANY), }; int r; @@ -305,17 +391,17 @@ static void test_sockaddr_equal(void) { union sockaddr_union a = { .in.sin_family = AF_INET, .in.sin_port = 0, - .in.sin_addr.s_addr = htonl(INADDR_ANY), + .in.sin_addr.s_addr = htobe32(INADDR_ANY), }; union sockaddr_union b = { .in.sin_family = AF_INET, .in.sin_port = 0, - .in.sin_addr.s_addr = htonl(INADDR_ANY), + .in.sin_addr.s_addr = htobe32(INADDR_ANY), }; union sockaddr_union c = { .in.sin_family = AF_INET, .in.sin_port = 0, - .in.sin_addr.s_addr = htonl(1234), + .in.sin_addr.s_addr = htobe32(1234), }; union sockaddr_union d = { .in6.sin6_family = AF_INET6, @@ -329,10 +415,27 @@ static void test_sockaddr_equal(void) { assert_se(!sockaddr_equal(&b, &c)); } +static void test_sockaddr_un_len(void) { + static const struct sockaddr_un fs = { + .sun_family = AF_UNIX, + .sun_path = "/foo/bar/waldo", + }; + + static const struct sockaddr_un abstract = { + .sun_family = AF_UNIX, + .sun_path = "\0foobar", + }; + + assert_se(SOCKADDR_UN_LEN(fs) == offsetof(struct sockaddr_un, sun_path) + strlen(fs.sun_path)); + assert_se(SOCKADDR_UN_LEN(abstract) == offsetof(struct sockaddr_un, sun_path) + 1 + strlen(abstract.sun_path + 1)); +} + int main(int argc, char *argv[]) { log_set_max_level(LOG_DEBUG); + test_ifname_valid(); + test_socket_address_parse(); test_socket_address_parse_netlink(); test_socket_address_equal(); @@ -340,13 +443,18 @@ int main(int argc, char *argv[]) { test_socket_address_is(); test_socket_address_is_netlink(); + test_in_addr_is_null(); test_in_addr_prefix_intersect(); test_in_addr_prefix_next(); test_in_addr_to_string(); + test_in_addr_ifindex_to_string(); + test_in_addr_ifindex_from_string_auto(); test_nameinfo_pretty(); test_sockaddr_equal(); + test_sockaddr_un_len(); + return 0; } diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c new file mode 100644 index 0000000000..6c34250a01 --- /dev/null +++ b/src/test/test-stat-util.c @@ -0,0 +1,68 @@ +/*** + This file is part of systemd. + + Copyright 2010 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> +#include <unistd.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "macro.h" +#include "stat-util.h" + +static void test_files_same(void) { + _cleanup_close_ int fd = -1; + char name[] = "/tmp/test-files_same.XXXXXX"; + char name_alias[] = "/tmp/test-files_same.alias"; + + fd = mkostemp_safe(name); + assert_se(fd >= 0); + assert_se(symlink(name, name_alias) >= 0); + + assert_se(files_same(name, name)); + assert_se(files_same(name, name_alias)); + + unlink(name); + unlink(name_alias); +} + +static void test_is_symlink(void) { + char name[] = "/tmp/test-is_symlink.XXXXXX"; + char name_link[] = "/tmp/test-is_symlink.link"; + _cleanup_close_ int fd = -1; + + fd = mkostemp_safe(name); + assert_se(fd >= 0); + assert_se(symlink(name, name_link) >= 0); + + assert_se(is_symlink(name) == 0); + assert_se(is_symlink(name_link) == 1); + assert_se(is_symlink("/a/file/which/does/not/exist/i/guess") < 0); + + + unlink(name); + unlink(name_link); +} + +int main(int argc, char *argv[]) { + test_files_same(); + test_is_symlink(); + + return 0; +} diff --git a/src/test/test-strbuf.c b/src/test/test-strbuf.c index 4ec648ae66..513218c397 100644 --- a/src/test/test-strbuf.c +++ b/src/test/test-strbuf.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,6 +21,7 @@ #include <string.h> #include "strbuf.h" +#include "string-util.h" #include "strv.h" #include "util.h" diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c new file mode 100644 index 0000000000..d0f84d70bc --- /dev/null +++ b/src/test/test-string-util.c @@ -0,0 +1,370 @@ +/*** + 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 "alloc-util.h" +#include "macro.h" +#include "string-util.h" +#include "strv.h" + +static void test_string_erase(void) { + char *x; + + x = strdupa(""); + assert_se(streq(string_erase(x), "")); + + x = strdupa("1"); + assert_se(streq(string_erase(x), "x")); + + x = strdupa("12"); + assert_se(streq(string_erase(x), "xx")); + + x = strdupa("123"); + assert_se(streq(string_erase(x), "xxx")); + + x = strdupa("1234"); + assert_se(streq(string_erase(x), "xxxx")); + + x = strdupa("12345"); + assert_se(streq(string_erase(x), "xxxxx")); + + x = strdupa("123456"); + assert_se(streq(string_erase(x), "xxxxxx")); + + x = strdupa("1234567"); + assert_se(streq(string_erase(x), "xxxxxxx")); + + x = strdupa("12345678"); + assert_se(streq(string_erase(x), "xxxxxxxx")); + + x = strdupa("123456789"); + assert_se(streq(string_erase(x), "xxxxxxxxx")); +} + +static void test_ascii_strcasecmp_n(void) { + + assert_se(ascii_strcasecmp_n("", "", 0) == 0); + assert_se(ascii_strcasecmp_n("", "", 1) == 0); + assert_se(ascii_strcasecmp_n("", "a", 1) < 0); + assert_se(ascii_strcasecmp_n("", "a", 2) < 0); + assert_se(ascii_strcasecmp_n("a", "", 1) > 0); + assert_se(ascii_strcasecmp_n("a", "", 2) > 0); + assert_se(ascii_strcasecmp_n("a", "a", 1) == 0); + assert_se(ascii_strcasecmp_n("a", "a", 2) == 0); + assert_se(ascii_strcasecmp_n("a", "b", 1) < 0); + assert_se(ascii_strcasecmp_n("a", "b", 2) < 0); + assert_se(ascii_strcasecmp_n("b", "a", 1) > 0); + assert_se(ascii_strcasecmp_n("b", "a", 2) > 0); + assert_se(ascii_strcasecmp_n("xxxxyxxxx", "xxxxYxxxx", 9) == 0); + assert_se(ascii_strcasecmp_n("xxxxxxxxx", "xxxxyxxxx", 9) < 0); + assert_se(ascii_strcasecmp_n("xxxxXxxxx", "xxxxyxxxx", 9) < 0); + assert_se(ascii_strcasecmp_n("xxxxxxxxx", "xxxxYxxxx", 9) < 0); + assert_se(ascii_strcasecmp_n("xxxxXxxxx", "xxxxYxxxx", 9) < 0); + + assert_se(ascii_strcasecmp_n("xxxxYxxxx", "xxxxYxxxx", 9) == 0); + assert_se(ascii_strcasecmp_n("xxxxyxxxx", "xxxxxxxxx", 9) > 0); + assert_se(ascii_strcasecmp_n("xxxxyxxxx", "xxxxXxxxx", 9) > 0); + assert_se(ascii_strcasecmp_n("xxxxYxxxx", "xxxxxxxxx", 9) > 0); + assert_se(ascii_strcasecmp_n("xxxxYxxxx", "xxxxXxxxx", 9) > 0); +} + +static void test_ascii_strcasecmp_nn(void) { + assert_se(ascii_strcasecmp_nn("", 0, "", 0) == 0); + assert_se(ascii_strcasecmp_nn("", 0, "", 1) < 0); + assert_se(ascii_strcasecmp_nn("", 1, "", 0) > 0); + assert_se(ascii_strcasecmp_nn("", 1, "", 1) == 0); + + assert_se(ascii_strcasecmp_nn("aaaa", 4, "aaAa", 4) == 0); + assert_se(ascii_strcasecmp_nn("aaa", 3, "aaAa", 4) < 0); + assert_se(ascii_strcasecmp_nn("aaa", 4, "aaAa", 4) < 0); + assert_se(ascii_strcasecmp_nn("aaaa", 4, "aaA", 3) > 0); + assert_se(ascii_strcasecmp_nn("aaaa", 4, "AAA", 4) > 0); + + assert_se(ascii_strcasecmp_nn("aaaa", 4, "bbbb", 4) < 0); + assert_se(ascii_strcasecmp_nn("aaAA", 4, "BBbb", 4) < 0); + assert_se(ascii_strcasecmp_nn("BBbb", 4, "aaaa", 4) > 0); +} + +static void test_streq_ptr(void) { + assert_se(streq_ptr(NULL, NULL)); + assert_se(!streq_ptr("abc", "cdef")); +} + +static void test_strstrip(void) { + char *r; + char input[] = " hello, waldo. "; + + r = strstrip(input); + assert_se(streq(r, "hello, waldo.")); +} + +static void test_strextend(void) { + _cleanup_free_ char *str = strdup("0123"); + strextend(&str, "456", "78", "9", NULL); + assert_se(streq(str, "0123456789")); +} + +static void test_strrep(void) { + _cleanup_free_ char *one, *three, *zero; + one = strrep("waldo", 1); + three = strrep("waldo", 3); + zero = strrep("waldo", 0); + + assert_se(streq(one, "waldo")); + assert_se(streq(three, "waldowaldowaldo")); + assert_se(streq(zero, "")); +} + + +static void test_strappend(void) { + _cleanup_free_ char *t1, *t2, *t3, *t4; + + t1 = strappend(NULL, NULL); + assert_se(streq(t1, "")); + + t2 = strappend(NULL, "suf"); + assert_se(streq(t2, "suf")); + + t3 = strappend("pre", NULL); + assert_se(streq(t3, "pre")); + + t4 = strappend("pre", "suf"); + assert_se(streq(t4, "presuf")); +} + +static void test_string_has_cc(void) { + assert_se(string_has_cc("abc\1", NULL)); + assert_se(string_has_cc("abc\x7f", NULL)); + assert_se(string_has_cc("abc\x7f", NULL)); + assert_se(string_has_cc("abc\t\x7f", "\t")); + assert_se(string_has_cc("abc\t\x7f", "\t")); + assert_se(string_has_cc("\x7f", "\t")); + assert_se(string_has_cc("\x7f", "\t\a")); + + assert_se(!string_has_cc("abc\t\t", "\t")); + assert_se(!string_has_cc("abc\t\t\a", "\t\a")); + assert_se(!string_has_cc("a\ab\tc", "\t\a")); +} + +static void test_ascii_strlower(void) { + char a[] = "AabBcC Jk Ii Od LKJJJ kkd LK"; + assert_se(streq(ascii_strlower(a), "aabbcc jk ii od lkjjj kkd lk")); +} + +static void test_strshorten(void) { + char s[] = "foobar"; + + assert_se(strlen(strshorten(s, 6)) == 6); + assert_se(strlen(strshorten(s, 12)) == 6); + assert_se(strlen(strshorten(s, 2)) == 2); + assert_se(strlen(strshorten(s, 0)) == 0); +} + +static void test_strjoina(void) { + char *actual; + + actual = strjoina("", "foo", "bar"); + assert_se(streq(actual, "foobar")); + + actual = strjoina("foo", "bar", "baz"); + assert_se(streq(actual, "foobarbaz")); + + 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_strcmp_ptr(void) { + assert_se(strcmp_ptr(NULL, NULL) == 0); + assert_se(strcmp_ptr("", NULL) > 0); + assert_se(strcmp_ptr("foo", NULL) > 0); + assert_se(strcmp_ptr(NULL, "") < 0); + assert_se(strcmp_ptr(NULL, "bar") < 0); + assert_se(strcmp_ptr("foo", "bar") > 0); + assert_se(strcmp_ptr("bar", "baz") < 0); + assert_se(strcmp_ptr("foo", "foo") == 0); + assert_se(strcmp_ptr("", "") == 0); +} + +static void test_foreach_word(void) { + const char *word, *state; + size_t l; + int i = 0; + const char test[] = "test abc d\te f "; + const char * const expected[] = { + "test", + "abc", + "d", + "e", + "f", + "", + NULL + }; + + FOREACH_WORD(word, l, test, state) + assert_se(strneq(expected[i++], word, l)); +} + +static void check(const char *test, char** expected, bool trailing) { + const char *word, *state; + size_t l; + int i = 0; + + printf("<<<%s>>>\n", test); + FOREACH_WORD_QUOTED(word, l, test, state) { + _cleanup_free_ char *t = NULL; + + assert_se(t = strndup(word, l)); + assert_se(strneq(expected[i++], word, l)); + printf("<%s>\n", t); + } + 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_endswith(void) { + assert_se(endswith("foobar", "bar")); + assert_se(endswith("foobar", "")); + assert_se(endswith("foobar", "foobar")); + assert_se(endswith("", "")); + + assert_se(!endswith("foobar", "foo")); + assert_se(!endswith("foobar", "foobarfoofoo")); +} + +static void test_endswith_no_case(void) { + assert_se(endswith_no_case("fooBAR", "bar")); + assert_se(endswith_no_case("foobar", "")); + assert_se(endswith_no_case("foobar", "FOOBAR")); + assert_se(endswith_no_case("", "")); + + assert_se(!endswith_no_case("foobar", "FOO")); + assert_se(!endswith_no_case("foobar", "FOOBARFOOFOO")); +} + +static void test_delete_chars(void) { + char *r; + char input[] = " hello, waldo. abc"; + + r = delete_chars(input, WHITESPACE); + assert_se(streq(r, "hello,waldo.abc")); +} + +static void test_in_charset(void) { + assert_se(in_charset("dddaaabbbcccc", "abcd")); + assert_se(!in_charset("dddaaabbbcccc", "abc f")); +} + +static void test_split_pair(void) { + _cleanup_free_ char *a = NULL, *b = NULL; + + assert_se(split_pair("", "", &a, &b) == -EINVAL); + assert_se(split_pair("foo=bar", "", &a, &b) == -EINVAL); + assert_se(split_pair("", "=", &a, &b) == -EINVAL); + assert_se(split_pair("foo=bar", "=", &a, &b) >= 0); + assert_se(streq(a, "foo")); + assert_se(streq(b, "bar")); + free(a); + free(b); + assert_se(split_pair("==", "==", &a, &b) >= 0); + assert_se(streq(a, "")); + assert_se(streq(b, "")); + free(a); + free(b); + + assert_se(split_pair("===", "==", &a, &b) >= 0); + assert_se(streq(a, "")); + assert_se(streq(b, "=")); +} + +static void test_first_word(void) { + assert_se(first_word("Hello", "")); + assert_se(first_word("Hello", "Hello")); + assert_se(first_word("Hello world", "Hello")); + assert_se(first_word("Hello\tworld", "Hello")); + assert_se(first_word("Hello\nworld", "Hello")); + assert_se(first_word("Hello\rworld", "Hello")); + assert_se(first_word("Hello ", "Hello")); + + assert_se(!first_word("Hello", "Hellooo")); + assert_se(!first_word("Hello", "xxxxx")); + assert_se(!first_word("Hellooo", "Hello")); +} + +int main(int argc, char *argv[]) { + test_string_erase(); + test_ascii_strcasecmp_n(); + test_ascii_strcasecmp_nn(); + test_streq_ptr(); + test_strstrip(); + test_strextend(); + test_strrep(); + test_strappend(); + test_string_has_cc(); + test_ascii_strlower(); + test_strshorten(); + test_strjoina(); + test_strcmp_ptr(); + test_foreach_word(); + test_foreach_word_quoted(); + test_endswith(); + test_endswith_no_case(); + test_delete_chars(); + test_in_charset(); + test_split_pair(); + test_first_word(); + + return 0; +} diff --git a/src/test/test-strip-tab-ansi.c b/src/test/test-strip-tab-ansi.c index 358454842a..72b0f6fc11 100644 --- a/src/test/test-strip-tab-ansi.c +++ b/src/test/test-strip-tab-ansi.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,8 +19,9 @@ #include <stdio.h> -#include "util.h" +#include "string-util.h" #include "terminal-util.h" +#include "util.h" int main(int argc, char *argv[]) { char *p; @@ -33,13 +32,13 @@ int main(int argc, char *argv[]) { assert_se(streq(p, " Foobar bar waldo ")); free(p); - assert_se(p = strdup(ANSI_HIGHLIGHT_ON "Hello" ANSI_HIGHLIGHT_OFF ANSI_HIGHLIGHT_RED_ON " world!" ANSI_HIGHLIGHT_OFF)); + assert_se(p = strdup(ANSI_HIGHLIGHT "Hello" ANSI_NORMAL ANSI_HIGHLIGHT_RED " world!" ANSI_NORMAL)); assert_se(strip_tab_ansi(&p, NULL)); fprintf(stdout, "<%s>\n", p); assert_se(streq(p, "Hello world!")); free(p); - assert_se(p = strdup("\x1B[\x1B[\t\x1B[" ANSI_HIGHLIGHT_ON "\x1B[" "Hello" ANSI_HIGHLIGHT_OFF ANSI_HIGHLIGHT_RED_ON " world!" ANSI_HIGHLIGHT_OFF)); + assert_se(p = strdup("\x1B[\x1B[\t\x1B[" ANSI_HIGHLIGHT "\x1B[" "Hello" ANSI_NORMAL ANSI_HIGHLIGHT_RED " world!" ANSI_NORMAL)); assert_se(strip_tab_ansi(&p, NULL)); assert_se(streq(p, "\x1B[\x1B[ \x1B[\x1B[Hello world!")); free(p); diff --git a/src/test/test-strv.c b/src/test/test-strv.c index d5ea2b3fab..88da69e2d7 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,9 +20,11 @@ #include <string.h> -#include "util.h" +#include "alloc-util.h" #include "specifier.h" +#include "string-util.h" #include "strv.h" +#include "util.h" static void test_specifier_printf(void) { static const Specifier table[] = { @@ -54,6 +54,25 @@ static void test_specifier_printf(void) { puts(w); } +static void test_str_in_set(void) { + assert_se(STR_IN_SET("x", "x", "y", "z")); + assert_se(!STR_IN_SET("X", "x", "y", "z")); + assert_se(!STR_IN_SET("", "x", "y", "z")); + assert_se(STR_IN_SET("x", "w", "x")); +} + +static void test_strptr_in_set(void) { + assert_se(STRPTR_IN_SET("x", "x", "y", "z")); + assert_se(!STRPTR_IN_SET("X", "x", "y", "z")); + assert_se(!STRPTR_IN_SET("", "x", "y", "z")); + assert_se(STRPTR_IN_SET("x", "w", "x")); + + assert_se(!STRPTR_IN_SET(NULL, "x", "y", "z")); + assert_se(!STRPTR_IN_SET(NULL, "")); + /* strv cannot contain a null, hence the result below */ + assert_se(!STRPTR_IN_SET(NULL, NULL)); +} + static const char* const input_table_multiple[] = { "one", "two", @@ -70,6 +89,18 @@ static const char* const input_table_none[] = { NULL, }; +static const char* const input_table_two_empties[] = { + "", + "", + NULL, +}; + +static const char* const input_table_one_empty[] = { + "", + NULL, +}; + + static const char* const input_table_quotes[] = { "\"", "'", @@ -130,7 +161,7 @@ static void test_strv_find_startswith(void) { } static void test_strv_join(void) { - _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL; + _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL; p = strv_join((char **)input_table_multiple, ", "); assert_se(p); @@ -151,11 +182,19 @@ static void test_strv_join(void) { t = strv_join((char **)input_table_none, ", "); assert_se(t); assert_se(streq(t, "")); + + v = strv_join((char **)input_table_two_empties, ", "); + assert_se(v); + assert_se(streq(v, ", ")); + + w = strv_join((char **)input_table_one_empty, ", "); + assert_se(w); + assert_se(streq(w, "")); } static void test_strv_quote_unquote(const char* const *split, const char *quoted) { _cleanup_free_ char *p; - _cleanup_strv_free_ char **s; + _cleanup_strv_free_ char **s = NULL; char **t; int r; @@ -165,8 +204,8 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted assert_se(p); assert_se(streq(p, quoted)); - r = strv_split_quoted(&s, quoted, 0); - assert_se(r == 0); + r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES); + assert_se(r == (int) strv_length(s)); assert_se(s); STRV_FOREACH(t, s) { assert_se(*t); @@ -182,8 +221,8 @@ static void test_strv_unquote(const char *quoted, char **list) { char **t; int r; - r = strv_split_quoted(&s, quoted, 0); - assert_se(r == 0); + r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES); + assert_se(r == (int) strv_length(list)); assert_se(s); j = strv_join(s, " | "); assert_se(j); @@ -199,7 +238,7 @@ static void test_invalid_unquote(const char *quoted) { char **s = NULL; int r; - r = strv_split_quoted(&s, quoted, 0); + r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES); assert_se(s == NULL); assert_se(r == -EINVAL); } @@ -219,6 +258,21 @@ static void test_strv_split(void) { } } +static void test_strv_split_extract(void) { + _cleanup_strv_free_ char **l = NULL; + const char *str = ":foo\\:bar::waldo:"; + int r; + + r = strv_split_extract(&l, str, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + assert_se(r == (int) strv_length(l)); + assert_se(streq_ptr(l[0], "")); + assert_se(streq_ptr(l[1], "foo:bar")); + assert_se(streq_ptr(l[2], "")); + assert_se(streq_ptr(l[3], "waldo")); + assert_se(streq_ptr(l[4], "")); + assert_se(streq_ptr(l[5], NULL)); +} + static void test_strv_split_newlines(void) { unsigned i = 0; char **s; @@ -307,7 +361,7 @@ static void test_strv_sort(void) { } static void test_strv_extend_strv_concat(void) { - _cleanup_strv_free_ char **a = NULL, **b = NULL; + _cleanup_strv_free_ char **a = NULL, **b = NULL; a = strv_new("without", "suffix", NULL); b = strv_new("with", "suffix", NULL); @@ -323,14 +377,14 @@ static void test_strv_extend_strv_concat(void) { } static void test_strv_extend_strv(void) { - _cleanup_strv_free_ char **a = NULL, **b = NULL; + _cleanup_strv_free_ char **a = NULL, **b = NULL, **n = NULL; a = strv_new("abc", "def", "ghi", NULL); - b = strv_new("jkl", "mno", "pqr", NULL); + b = strv_new("jkl", "mno", "abc", "pqr", NULL); assert_se(a); assert_se(b); - assert_se(strv_extend_strv(&a, b) >= 0); + assert_se(strv_extend_strv(&a, b, true) == 3); assert_se(streq(a[0], "abc")); assert_se(streq(a[1], "def")); @@ -338,8 +392,14 @@ static void test_strv_extend_strv(void) { assert_se(streq(a[3], "jkl")); assert_se(streq(a[4], "mno")); assert_se(streq(a[5], "pqr")); - assert_se(strv_length(a) == 6); + + assert_se(strv_extend_strv(&n, b, false) >= 0); + assert_se(streq(n[0], "jkl")); + assert_se(streq(n[1], "mno")); + assert_se(streq(n[2], "abc")); + assert_se(streq(n[3], "pqr")); + assert_se(strv_length(n) == 4); } static void test_strv_extend(void) { @@ -393,9 +453,14 @@ static void test_strv_foreach_backwards(void) { assert_se(a); - STRV_FOREACH_BACKWARDS(check, a) { + STRV_FOREACH_BACKWARDS(check, a) assert_se(streq_ptr(*check, input_table_multiple[i--])); - } + + STRV_FOREACH_BACKWARDS(check, (char**) NULL) + assert_not_reached("Let's see that we check empty strv right, too."); + + STRV_FOREACH_BACKWARDS(check, (char**) { NULL }) + assert_not_reached("Let's see that we check empty strv right, too."); } static void test_strv_foreach_pair(void) { @@ -542,8 +607,128 @@ static void test_strv_reverse(void) { assert_se(streq_ptr(d[3], NULL)); } +static void test_strv_shell_escape(void) { + _cleanup_strv_free_ char **v = NULL; + + v = strv_new("foo:bar", "bar,baz", "wal\\do", NULL); + assert_se(v); + assert_se(strv_shell_escape(v, ",:")); + assert_se(streq_ptr(v[0], "foo\\:bar")); + assert_se(streq_ptr(v[1], "bar\\,baz")); + assert_se(streq_ptr(v[2], "wal\\\\do")); + assert_se(streq_ptr(v[3], NULL)); +} + +static void test_strv_skip_one(char **a, size_t n, char **b) { + a = strv_skip(a, n); + assert_se(strv_equal(a, b)); +} + +static void test_strv_skip(void) { + test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 0, STRV_MAKE("foo", "bar", "baz")); + test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 1, STRV_MAKE("bar", "baz")); + test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 2, STRV_MAKE("baz")); + test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 3, STRV_MAKE(NULL)); + test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 4, STRV_MAKE(NULL)); + test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 55, STRV_MAKE(NULL)); + + test_strv_skip_one(STRV_MAKE("quux"), 0, STRV_MAKE("quux")); + test_strv_skip_one(STRV_MAKE("quux"), 1, STRV_MAKE(NULL)); + test_strv_skip_one(STRV_MAKE("quux"), 55, STRV_MAKE(NULL)); + + test_strv_skip_one(STRV_MAKE(NULL), 0, STRV_MAKE(NULL)); + test_strv_skip_one(STRV_MAKE(NULL), 1, STRV_MAKE(NULL)); + test_strv_skip_one(STRV_MAKE(NULL), 55, STRV_MAKE(NULL)); +} + +static void test_strv_extend_n(void) { + _cleanup_strv_free_ char **v = NULL; + + v = strv_new("foo", "bar", NULL); + assert_se(v); + + assert_se(strv_extend_n(&v, "waldo", 3) >= 0); + assert_se(strv_extend_n(&v, "piep", 2) >= 0); + + assert_se(streq(v[0], "foo")); + assert_se(streq(v[1], "bar")); + assert_se(streq(v[2], "waldo")); + assert_se(streq(v[3], "waldo")); + assert_se(streq(v[4], "waldo")); + assert_se(streq(v[5], "piep")); + assert_se(streq(v[6], "piep")); + assert_se(v[7] == NULL); + + v = strv_free(v); + + assert_se(strv_extend_n(&v, "foo", 1) >= 0); + assert_se(strv_extend_n(&v, "bar", 0) >= 0); + + assert_se(streq(v[0], "foo")); + assert_se(v[1] == NULL); +} + +static void test_strv_make_nulstr_one(char **l) { + _cleanup_free_ char *b = NULL, *c = NULL; + _cleanup_strv_free_ char **q = NULL; + const char *s = NULL; + size_t n, m; + unsigned i = 0; + + assert_se(strv_make_nulstr(l, &b, &n) >= 0); + assert_se(q = strv_parse_nulstr(b, n)); + assert_se(strv_equal(l, q)); + + assert_se(strv_make_nulstr(q, &c, &m) >= 0); + assert_se(m == n); + assert_se(memcmp(b, c, m) == 0); + + NULSTR_FOREACH(s, b) + assert_se(streq(s, l[i++])); + assert_se(i == strv_length(l)); +} + +static void test_strv_make_nulstr(void) { + test_strv_make_nulstr_one(NULL); + test_strv_make_nulstr_one(STRV_MAKE(NULL)); + test_strv_make_nulstr_one(STRV_MAKE("foo")); + test_strv_make_nulstr_one(STRV_MAKE("foo", "bar")); + test_strv_make_nulstr_one(STRV_MAKE("foo", "bar", "quuux")); +} + +static void test_foreach_string(void) { + const char * const t[] = { + "foo", + "bar", + "waldo", + NULL + }; + const char *x; + unsigned i = 0; + + FOREACH_STRING(x, "foo", "bar", "waldo") + assert_se(streq_ptr(t[i++], x)); + + assert_se(i == 3); + + FOREACH_STRING(x, "zzz") + assert_se(streq(x, "zzz")); +} + +static void test_strv_fnmatch(void) { + _cleanup_strv_free_ char **v = NULL; + + assert_se(!strv_fnmatch(STRV_MAKE_EMPTY, "a", 0)); + + v = strv_new("*\\*", NULL); + assert_se(!strv_fnmatch(v, "\\", 0)); + assert_se(strv_fnmatch(v, "\\", FNM_NOESCAPE)); +} + int main(int argc, char *argv[]) { test_specifier_printf(); + test_str_in_set(); + test_strptr_in_set(); test_strv_foreach(); test_strv_foreach_backwards(); test_strv_foreach_pair(); @@ -555,6 +740,8 @@ int main(int argc, char *argv[]) { test_strv_quote_unquote(input_table_multiple, "\"one\" \"two\" \"three\""); test_strv_quote_unquote(input_table_one, "\"one\""); test_strv_quote_unquote(input_table_none, ""); + test_strv_quote_unquote(input_table_one_empty, "\"\""); + test_strv_quote_unquote(input_table_two_empties, "\"\" \"\""); test_strv_quote_unquote(input_table_quotes, QUOTES_STRING); test_strv_quote_unquote(input_table_spaces, SPACES_STRING); @@ -583,6 +770,7 @@ int main(int argc, char *argv[]) { test_invalid_unquote("'x'y'g"); test_strv_split(); + test_strv_split_extract(); test_strv_split_newlines(); test_strv_split_nulstr(); test_strv_parse_nulstr(); @@ -598,6 +786,13 @@ int main(int argc, char *argv[]) { test_strv_equal(); test_strv_is_uniq(); test_strv_reverse(); + test_strv_shell_escape(); + test_strv_skip(); + test_strv_extend_n(); + test_strv_make_nulstr(); + + test_foreach_string(); + test_strv_fnmatch(); return 0; } diff --git a/src/test/test-strxcpyx.c b/src/test/test-strxcpyx.c index 858a4081da..9bea770131 100644 --- a/src/test/test-strxcpyx.c +++ b/src/test/test-strxcpyx.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,8 +19,9 @@ #include <string.h> -#include "util.h" +#include "string-util.h" #include "strxcpyx.h" +#include "util.h" static void test_strpcpy(void) { char target[25]; diff --git a/src/test/test-tables.c b/src/test/test-tables.c index 0e5ab1645f..0be74921fc 100644 --- a/src/test/test-tables.c +++ b/src/test/test-tables.c @@ -17,7 +17,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "architecture.h" #include "automount.h" +#include "busname.h" #include "cgroup.h" #include "compress.h" #include "condition.h" @@ -25,31 +27,27 @@ #include "execute.h" #include "install.h" #include "job.h" +#include "journald-server.h" #include "kill.h" +#include "link-config.h" +#include "locale-util.h" #include "log.h" #include "logs-show.h" #include "mount.h" #include "path.h" +#include "rlimit-util.h" #include "scope.h" #include "service.h" #include "slice.h" -#include "snapshot.h" #include "socket-util.h" #include "socket.h" #include "swap.h" #include "target.h" +#include "test-tables.h" #include "timer.h" #include "unit-name.h" #include "unit.h" #include "util.h" -#include "architecture.h" -#include "link-config.h" -#include "bus-xml-policy.h" -#include "busname.h" -#include "journald-server.h" -#include "locale-util.h" - -#include "test-tables.h" int main(int argc, char **argv) { test_table(architecture, ARCHITECTURE); @@ -84,8 +82,6 @@ int main(int argc, char **argv) { test_table(path_result, PATH_RESULT); test_table(path_state, PATH_STATE); test_table(path_type, PATH_TYPE); - test_table(policy_item_class, POLICY_ITEM_CLASS); - test_table(policy_item_type, POLICY_ITEM_TYPE); test_table(protect_home, PROTECT_HOME); test_table(protect_system, PROTECT_SYSTEM); test_table(rlimit, RLIMIT); @@ -97,7 +93,6 @@ int main(int argc, char **argv) { test_table(service_state, SERVICE_STATE); test_table(service_type, SERVICE_TYPE); test_table(slice_state, SLICE_STATE); - test_table(snapshot_state, SNAPSHOT_STATE); test_table(socket_address_bind_ipv6_only, SOCKET_ADDRESS_BIND_IPV6_ONLY); test_table(socket_exec_command, SOCKET_EXEC_COMMAND); test_table(socket_result, SOCKET_RESULT); diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c index d81fdb9923..373a1b70ba 100644 --- a/src/test/test-terminal-util.c +++ b/src/test/test-terminal-util.c @@ -18,13 +18,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <stdbool.h> +#include <stdio.h> -#include "terminal-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "log.h" #include "macro.h" +#include "terminal-util.h" #include "util.h" -#include "log.h" static void test_default_term_for_tty(void) { puts(default_term_for_tty("/dev/tty23")); @@ -48,7 +50,7 @@ static void test_read_one_char(void) { char name[] = "/tmp/test-read_one_char.XXXXXX"; int fd; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); file = fdopen(fd, "r+"); assert_se(file); diff --git a/src/test/test-time.c b/src/test/test-time.c index 3840fff061..7078a0374d 100644 --- a/src/test/test-time.c +++ b/src/test/test-time.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,8 +17,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "time-util.h" #include "strv.h" +#include "time-util.h" +#include "random-util.h" static void test_parse_sec(void) { usec_t u; @@ -57,6 +56,28 @@ static void test_parse_sec(void) { assert_se(parse_sec(".3 infinity", &u) < 0); } +static void test_parse_time(void) { + usec_t u; + + assert_se(parse_time("5", &u, 1) >= 0); + assert_se(u == 5); + + assert_se(parse_time("5", &u, USEC_PER_MSEC) >= 0); + assert_se(u == 5 * USEC_PER_MSEC); + + assert_se(parse_time("5", &u, USEC_PER_SEC) >= 0); + assert_se(u == 5 * USEC_PER_SEC); + + assert_se(parse_time("5s", &u, 1) >= 0); + assert_se(u == 5 * USEC_PER_SEC); + + assert_se(parse_time("5s", &u, USEC_PER_SEC) >= 0); + assert_se(u == 5 * USEC_PER_SEC); + + assert_se(parse_time("5s", &u, USEC_PER_MSEC) >= 0); + assert_se(u == 5 * USEC_PER_SEC); +} + static void test_parse_nsec(void) { nsec_t u; @@ -154,19 +175,97 @@ static void test_get_timezones(void) { r = get_timezones(&zones); assert_se(r == 0); - STRV_FOREACH(zone, zones) { + STRV_FOREACH(zone, zones) assert_se(timezone_is_valid(*zone)); +} + +static void test_usec_add(void) { + assert_se(usec_add(0, 0) == 0); + assert_se(usec_add(1, 4) == 5); + assert_se(usec_add(USEC_INFINITY, 5) == USEC_INFINITY); + assert_se(usec_add(5, USEC_INFINITY) == USEC_INFINITY); + assert_se(usec_add(USEC_INFINITY-5, 2) == USEC_INFINITY-3); + assert_se(usec_add(USEC_INFINITY-2, 2) == USEC_INFINITY); + assert_se(usec_add(USEC_INFINITY-1, 2) == USEC_INFINITY); + assert_se(usec_add(USEC_INFINITY, 2) == USEC_INFINITY); +} + +static void test_usec_sub(void) { + assert_se(usec_sub(0, 0) == 0); + assert_se(usec_sub(4, 1) == 3); + assert_se(usec_sub(4, 4) == 0); + assert_se(usec_sub(4, 5) == 0); + assert_se(usec_sub(USEC_INFINITY-3, -3) == USEC_INFINITY); + assert_se(usec_sub(USEC_INFINITY-3, -3) == USEC_INFINITY); + assert_se(usec_sub(USEC_INFINITY-3, -4) == USEC_INFINITY); + assert_se(usec_sub(USEC_INFINITY-3, -5) == USEC_INFINITY); + assert_se(usec_sub(USEC_INFINITY, 5) == USEC_INFINITY); +} + +static void test_format_timestamp(void) { + unsigned i; + + for (i = 0; i < 100; i++) { + char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESPAN_MAX)]; + usec_t x, y; + + random_bytes(&x, sizeof(x)); + x = x % (2147483600 * USEC_PER_SEC) + 1; + + assert_se(format_timestamp(buf, sizeof(buf), x)); + log_info("%s", buf); + assert_se(parse_timestamp(buf, &y) >= 0); + assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC); + + assert_se(format_timestamp_utc(buf, sizeof(buf), x)); + log_info("%s", buf); + assert_se(parse_timestamp(buf, &y) >= 0); + assert_se(x / USEC_PER_SEC == y / USEC_PER_SEC); + + assert_se(format_timestamp_us(buf, sizeof(buf), x)); + log_info("%s", buf); + assert_se(parse_timestamp(buf, &y) >= 0); + assert_se(x == y); + + assert_se(format_timestamp_us_utc(buf, sizeof(buf), x)); + log_info("%s", buf); + assert_se(parse_timestamp(buf, &y) >= 0); + assert_se(x == y); + + assert_se(format_timestamp_relative(buf, sizeof(buf), x)); + log_info("%s", buf); + assert_se(parse_timestamp(buf, &y) >= 0); + + /* The two calls above will run with a slightly different local time. Make sure we are in the same + * range however, but give enough leeway that this is unlikely to explode. And of course, + * format_timestamp_relative() scales the accuracy with the distance from the current time up to one + * month, cover for that too. */ + assert_se(y > x ? y - x : x - y <= USEC_PER_MONTH + USEC_PER_DAY); } } int main(int argc, char *argv[]) { + uintmax_t x; + test_parse_sec(); + test_parse_time(); test_parse_nsec(); test_format_timespan(1); test_format_timespan(USEC_PER_MSEC); test_format_timespan(USEC_PER_SEC); test_timezone_is_valid(); test_get_timezones(); + test_usec_add(); + test_usec_sub(); + test_format_timestamp(); + + /* Ensure time_t is signed */ + assert_cc((time_t) -1 < (time_t) 1); + + /* Ensure TIME_T_MAX works correctly */ + x = (uintmax_t) TIME_T_MAX; + x++; + assert((time_t) x < 0); return 0; } diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c index 221dd67eb2..f35e6793b7 100644 --- a/src/test/test-tmpfiles.c +++ b/src/test/test-tmpfiles.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,31 +18,64 @@ ***/ #include <fcntl.h> -#include <unistd.h> -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> +#include <unistd.h> -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "fs-util.h" +#include "log.h" +#include "string-util.h" +#include "util.h" int main(int argc, char** argv) { + _cleanup_free_ char *cmd = NULL, *cmd2 = NULL, *ans = NULL, *ans2 = NULL, *d = NULL, *tmp = NULL, *line = NULL; + _cleanup_close_ int fd = -1, fd2 = -1; const char *p = argv[1] ?: "/tmp"; - char *pattern = strjoina(p, "/systemd-test-XXXXXX"); - _cleanup_close_ int fd, fd2; - _cleanup_free_ char *cmd, *cmd2; + char *pattern; - fd = open_tmpfile(p, O_RDWR|O_CLOEXEC); + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + + pattern = strjoina(p, "/systemd-test-XXXXXX"); + + fd = open_tmpfile_unlinkable(p, O_RDWR|O_CLOEXEC); assert_se(fd >= 0); assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd) > 0); - system(cmd); + (void) system(cmd); + assert_se(readlink_malloc(cmd + 6, &ans) >= 0); + log_debug("link1: %s", ans); + assert_se(endswith(ans, " (deleted)")); - fd2 = mkostemp_safe(pattern, O_RDWR|O_CLOEXEC); + fd2 = mkostemp_safe(pattern); assert_se(fd >= 0); assert_se(unlink(pattern) == 0); assert_se(asprintf(&cmd2, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd2) > 0); - system(cmd2); + (void) system(cmd2); + assert_se(readlink_malloc(cmd2 + 6, &ans2) >= 0); + log_debug("link2: %s", ans2); + assert_se(endswith(ans2, " (deleted)")); + + pattern = strjoina(p, "/tmpfiles-test"); + assert_se(tempfn_random(pattern, NULL, &d) >= 0); + + fd = open_tmpfile_linkable(d, O_RDWR|O_CLOEXEC, &tmp); + assert_se(fd >= 0); + assert_se(write(fd, "foobar\n", 7) == 7); + + assert_se(touch(d) >= 0); + assert_se(link_tmpfile(fd, tmp, d) == -EEXIST); + assert_se(unlink(d) >= 0); + assert_se(link_tmpfile(fd, tmp, d) >= 0); + + assert_se(read_one_line_file(d, &line) >= 0); + assert_se(streq(line, "foobar")); + assert_se(unlink(d) >= 0); return 0; } diff --git a/src/test/test-udev.c b/src/test/test-udev.c index 2b765a3e90..e965b4494a 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -18,58 +18,53 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <stdlib.h> #include <errno.h> -#include <unistd.h> #include <sched.h> +#include <stdio.h> +#include <stdlib.h> #include <sys/mount.h> #include <sys/signalfd.h> +#include <unistd.h> +#include "fs-util.h" +#include "log.h" #include "missing.h" #include "selinux-util.h" #include "signal-util.h" -#include "udev.h" +#include "string-util.h" #include "udev-util.h" +#include "udev.h" static int fake_filesystems(void) { static const struct fakefs { const char *src; const char *target; const char *error; + bool ignore_mount_error; } fakefss[] = { - { "test/sys", "/sys", "failed to mount test /sys" }, - { "test/dev", "/dev", "failed to mount test /dev" }, - { "test/run", "/run", "failed to mount test /run" }, - { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d" }, - { "test/run", "/usr/lib/udev/rules.d", "failed to mount empty /usr/lib/udev/rules.d" }, + { "test/tmpfs/sys", "/sys", "failed to mount test /sys", false }, + { "test/tmpfs/dev", "/dev", "failed to mount test /dev", false }, + { "test/run", "/run", "failed to mount test /run", false }, + { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d", true }, + { "test/run", UDEVLIBEXECDIR "/rules.d", "failed to mount empty " UDEVLIBEXECDIR "/rules.d", true }, }; unsigned int i; - int err; - err = unshare(CLONE_NEWNS); - if (err < 0) { - err = -errno; - fprintf(stderr, "failed to call unshare(): %m\n"); - goto out; - } + if (unshare(CLONE_NEWNS) < 0) + return log_error_errno(errno, "failed to call unshare(): %m"); - if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) { - err = -errno; - fprintf(stderr, "failed to mount / as private: %m\n"); - goto out; - } + if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) + return log_error_errno(errno, "failed to mount / as private: %m"); for (i = 0; i < ELEMENTSOF(fakefss); i++) { - err = mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL); - if (err < 0) { - err = -errno; - fprintf(stderr, "%s %m", fakefss[i].error); - return err; + if (mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL) < 0) { + log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "%s: %m", fakefss[i].error); + if (!fakefss[i].ignore_mount_error) + return -errno; } } -out: - return err; + + return 0; } int main(int argc, char *argv[]) { @@ -82,6 +77,9 @@ int main(int argc, char *argv[]) { const char *action; int err; + log_parse_environment(); + log_open(); + err = fake_filesystems(); if (err < 0) return EXIT_FAILURE; @@ -91,7 +89,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; log_debug("version %s", VERSION); - mac_selinux_init("/dev"); + mac_selinux_init(); action = argv[1]; if (action == NULL) { diff --git a/src/test/test-uid-range.c b/src/test/test-uid-range.c index bc5baa2fcb..41f06a5cec 100644 --- a/src/test/test-uid-range.c +++ b/src/test/test-uid-range.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,8 +19,10 @@ #include <stddef.h> -#include "util.h" +#include "alloc-util.h" #include "uid-range.h" +#include "user-util.h" +#include "util.h" int main(int argc, char *argv[]) { _cleanup_free_ UidRange *p = NULL; diff --git a/src/test/test-unaligned.c b/src/test/test-unaligned.c index 1754d06b2d..4f64398943 100644 --- a/src/test/test-unaligned.c +++ b/src/test/test-unaligned.c @@ -17,8 +17,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unaligned.h" #include "sparse-endian.h" +#include "unaligned.h" #include "util.h" static uint8_t data[] = { @@ -26,7 +26,7 @@ static uint8_t data[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, }; -int main(int argc, const char *argv[]) { +static void test_be(void) { uint8_t scratch[16]; assert_se(unaligned_read_be16(&data[0]) == 0x0001); @@ -91,3 +91,99 @@ int main(int argc, const char *argv[]) { unaligned_write_be64(&scratch[7], 0x0708090a0b0c0d0e); assert_se(memcmp(&scratch[7], &data[7], sizeof(uint64_t)) == 0); } + +static void test_le(void) { + uint8_t scratch[16]; + + assert_se(unaligned_read_le16(&data[0]) == 0x0100); + assert_se(unaligned_read_le16(&data[1]) == 0x0201); + + assert_se(unaligned_read_le32(&data[0]) == 0x03020100); + assert_se(unaligned_read_le32(&data[1]) == 0x04030201); + assert_se(unaligned_read_le32(&data[2]) == 0x05040302); + assert_se(unaligned_read_le32(&data[3]) == 0x06050403); + + assert_se(unaligned_read_le64(&data[0]) == 0x0706050403020100); + assert_se(unaligned_read_le64(&data[1]) == 0x0807060504030201); + assert_se(unaligned_read_le64(&data[2]) == 0x0908070605040302); + assert_se(unaligned_read_le64(&data[3]) == 0x0a09080706050403); + assert_se(unaligned_read_le64(&data[4]) == 0x0b0a090807060504); + assert_se(unaligned_read_le64(&data[5]) == 0x0c0b0a0908070605); + assert_se(unaligned_read_le64(&data[6]) == 0x0d0c0b0a09080706); + assert_se(unaligned_read_le64(&data[7]) == 0x0e0d0c0b0a090807); + + zero(scratch); + unaligned_write_le16(&scratch[0], 0x0100); + assert_se(memcmp(&scratch[0], &data[0], sizeof(uint16_t)) == 0); + zero(scratch); + unaligned_write_le16(&scratch[1], 0x0201); + assert_se(memcmp(&scratch[1], &data[1], sizeof(uint16_t)) == 0); + + zero(scratch); + unaligned_write_le32(&scratch[0], 0x03020100); + + assert_se(memcmp(&scratch[0], &data[0], sizeof(uint32_t)) == 0); + zero(scratch); + unaligned_write_le32(&scratch[1], 0x04030201); + assert_se(memcmp(&scratch[1], &data[1], sizeof(uint32_t)) == 0); + zero(scratch); + unaligned_write_le32(&scratch[2], 0x05040302); + assert_se(memcmp(&scratch[2], &data[2], sizeof(uint32_t)) == 0); + zero(scratch); + unaligned_write_le32(&scratch[3], 0x06050403); + assert_se(memcmp(&scratch[3], &data[3], sizeof(uint32_t)) == 0); + + zero(scratch); + unaligned_write_le64(&scratch[0], 0x0706050403020100); + assert_se(memcmp(&scratch[0], &data[0], sizeof(uint64_t)) == 0); + zero(scratch); + unaligned_write_le64(&scratch[1], 0x0807060504030201); + assert_se(memcmp(&scratch[1], &data[1], sizeof(uint64_t)) == 0); + zero(scratch); + unaligned_write_le64(&scratch[2], 0x0908070605040302); + assert_se(memcmp(&scratch[2], &data[2], sizeof(uint64_t)) == 0); + zero(scratch); + unaligned_write_le64(&scratch[3], 0x0a09080706050403); + assert_se(memcmp(&scratch[3], &data[3], sizeof(uint64_t)) == 0); + zero(scratch); + unaligned_write_le64(&scratch[4], 0x0B0A090807060504); + assert_se(memcmp(&scratch[4], &data[4], sizeof(uint64_t)) == 0); + zero(scratch); + unaligned_write_le64(&scratch[5], 0x0c0b0a0908070605); + assert_se(memcmp(&scratch[5], &data[5], sizeof(uint64_t)) == 0); + zero(scratch); + unaligned_write_le64(&scratch[6], 0x0d0c0b0a09080706); + assert_se(memcmp(&scratch[6], &data[6], sizeof(uint64_t)) == 0); + zero(scratch); + unaligned_write_le64(&scratch[7], 0x0e0d0c0b0a090807); + assert_se(memcmp(&scratch[7], &data[7], sizeof(uint64_t)) == 0); +} + +static void test_ne(void) { + uint16_t x = 4711; + uint32_t y = 123456; + uint64_t z = 9876543210; + + /* Note that we don't bother actually testing alignment issues in this function, after all the _ne() functions + * are just aliases for the _le() or _be() implementations, which we test extensively above. Hence, in this + * function, just ensure that they map to the right version on the local architecture. */ + + assert_se(unaligned_read_ne16(&x) == 4711); + assert_se(unaligned_read_ne32(&y) == 123456); + assert_se(unaligned_read_ne64(&z) == 9876543210); + + unaligned_write_ne16(&x, 1); + unaligned_write_ne32(&y, 2); + unaligned_write_ne64(&z, 3); + + assert_se(x == 1); + assert_se(y == 2); + assert_se(z == 3); +} + +int main(int argc, const char *argv[]) { + test_be(); + test_le(); + test_ne(); + return 0; +} diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index 8358789e6f..7ef087a2e3 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,23 +18,31 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> +#include <fcntl.h> #include <stddef.h> +#include <stdio.h> #include <string.h> +#include <sys/capability.h> #include <unistd.h> -#include <fcntl.h> -#include "install.h" -#include "install-printf.h" -#include "specifier.h" -#include "util.h" -#include "macro.h" +#include "alloc-util.h" +#include "capability-util.h" +#include "fd-util.h" +#include "fileio.h" #include "hashmap.h" +#include "hostname-util.h" +#include "install-printf.h" +#include "install.h" #include "load-fragment.h" +#include "macro.h" +#include "rm-rf.h" +#include "specifier.h" +#include "string-util.h" #include "strv.h" -#include "fileio.h" #include "test-helper.h" -#include "hostname-util.h" +#include "tests.h" +#include "user-util.h" +#include "util.h" static int test_unit_file_get_set(void) { int r; @@ -47,15 +53,15 @@ static int test_unit_file_get_set(void) { h = hashmap_new(&string_hash_ops); assert_se(h); - r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h); + r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL); if (r == -EPERM || r == -EACCES) { - printf("Skipping test: unit_file_get_list: %s", strerror(-r)); + log_notice_errno(r, "Skipping test: unit_file_get_list: %m"); return EXIT_TEST_SKIP; } - log_full(r == 0 ? LOG_INFO : LOG_ERR, - "unit_file_get_list: %s", strerror(-r)); + log_full_errno(r == 0 ? LOG_INFO : LOG_ERR, r, + "unit_file_get_list: %m"); if (r < 0) return EXIT_FAILURE; @@ -106,17 +112,30 @@ static void test_config_parse_exec(void) { ExecCommand *c = NULL, *c1; const char *ccc; + Manager *m = NULL; + Unit *u = NULL; + + r = manager_new(UNIT_FILE_USER, true, &m); + if (MANAGER_SKIP_TEST(r)) { + log_notice_errno(r, "Skipping test: manager_new: %m"); + return; + } + + assert_se(r >= 0); + assert_se(manager_startup(m, NULL, NULL) >= 0); + + assert_se(u = unit_new(m, sizeof(Service))); log_info("/* basic test */"); r = config_parse_exec(NULL, "fake", 1, "section", 1, "LValue", 0, "/RValue r1", - &c, NULL); + &c, u); assert_se(r >= 0); check_execcommand(c, "/RValue", "/RValue", "r1", NULL, false); r = config_parse_exec(NULL, "fake", 2, "section", 1, "LValue", 0, "/RValue///slashes r1///", - &c, NULL); + &c, u); log_info("/* test slashes */"); assert_se(r >= 0); @@ -126,14 +145,14 @@ static void test_config_parse_exec(void) { log_info("/* trailing slash */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "/RValue/ argv0 r1", - &c, NULL); + &c, u); 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", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/RValue/slashes2", "///argv0", "r1", NULL, false); @@ -141,21 +160,21 @@ static void test_config_parse_exec(void) { log_info("/* honour_argv0, no args */"); r = config_parse_exec(NULL, "fake", 3, "section", 1, "LValue", 0, "@/RValue", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* no command, whitespace only, reset */"); r = config_parse_exec(NULL, "fake", 3, "section", 1, "LValue", 0, " ", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c == NULL); log_info("/* ignore && honour_argv0 */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "-@/RValue///slashes3 argv0a r1", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c; check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true); @@ -163,7 +182,7 @@ static void test_config_parse_exec(void) { log_info("/* ignore && honour_argv0 */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "@-/RValue///slashes4 argv0b r1", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/RValue/slashes4", "argv0b", "r1", NULL, true); @@ -171,14 +190,14 @@ static void test_config_parse_exec(void) { log_info("/* ignore && ignore */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "--/RValue argv0 r1", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* ignore && ignore (2) */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "-@-/RValue argv0 r1", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); @@ -187,7 +206,7 @@ static void test_config_parse_exec(void) { "LValue", 0, "-@/RValue argv0 r1 ; " "/goo/goo boo", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); @@ -200,7 +219,7 @@ static void test_config_parse_exec(void) { "LValue", 0, "-@/RValue argv0 r1 ; ; " "/goo/goo boo", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); @@ -212,7 +231,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "-@/RValue argv0 r1 ; ", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); @@ -223,7 +242,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "-@/RValue argv0 r1 ;", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); @@ -234,7 +253,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "-@/RValue argv0 r1 ';'", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/RValue", "argv0", "r1", ";", true); @@ -243,7 +262,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "/bin/find \\;", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); @@ -252,7 +271,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "/sbin/find \\; /x", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -262,7 +281,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "/sbin/find \\;x", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -272,7 +291,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "/bin/find \\073", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); @@ -281,7 +300,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "/bin/find \";\"", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); @@ -290,7 +309,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "/sbin/find \";\" /x", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -300,7 +319,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "\"/PATH WITH SPACES/daemon\" -1 -2", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -310,7 +329,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "\"/PATH WITH SPACES/daemon -1 -2\"", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -320,7 +339,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -330,7 +349,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -340,7 +359,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -354,7 +373,7 @@ static void test_config_parse_exec(void) { log_info("/* invalid character: \\%c */", *ccc); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, path, - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); } @@ -362,7 +381,7 @@ static void test_config_parse_exec(void) { log_info("/* valid character: \\s */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "/path\\s", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/path ", NULL, NULL, NULL, false); @@ -371,7 +390,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "/bin/grep '\\w+\\K'", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/bin/grep", NULL, "\\w+\\K", NULL, false); @@ -381,46 +400,49 @@ static void test_config_parse_exec(void) { /* backslash is invalid */ r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "/path\\", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* missing ending ' */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "/path 'foo", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* missing ending ' with trailing backslash */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "/path 'foo\\", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* invalid space between modifiers */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "- /path", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* only modifiers, no path */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "-", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* empty argument, reset */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c == NULL); exec_command_free_list(c); + + unit_free(u); + manager_free(m); } #define env_file_1 \ @@ -463,7 +485,7 @@ static void test_load_env_file_1(void) { char name[] = "/tmp/test-load-env-file.XXXXXX"; _cleanup_close_ int fd; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); assert_se(write(fd, env_file_1, sizeof(env_file_1)) == sizeof(env_file_1)); @@ -486,7 +508,7 @@ static void test_load_env_file_2(void) { char name[] = "/tmp/test-load-env-file.XXXXXX"; _cleanup_close_ int fd; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); assert_se(write(fd, env_file_2, sizeof(env_file_2)) == sizeof(env_file_2)); @@ -504,7 +526,7 @@ static void test_load_env_file_3(void) { char name[] = "/tmp/test-load-env-file.XXXXXX"; _cleanup_close_ int fd; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); assert_se(write(fd, env_file_3, sizeof(env_file_3)) == sizeof(env_file_3)); @@ -520,7 +542,7 @@ static void test_load_env_file_4(void) { _cleanup_close_ int fd; int r; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); assert_se(write(fd, env_file_4, sizeof(env_file_4)) == sizeof(env_file_4)); @@ -540,7 +562,7 @@ static void test_load_env_file_5(void) { char name[] = "/tmp/test-load-env-file.XXXXXX"; _cleanup_close_ int fd; - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + fd = mkostemp_safe(name); assert_se(fd >= 0); assert_se(write(fd, env_file_5, sizeof(env_file_5)) == sizeof(env_file_5)); @@ -554,86 +576,285 @@ static void test_load_env_file_5(void) { static void test_install_printf(void) { char name[] = "name.service", - path[] = "/run/systemd/system/name.service", - user[] = "xxxx-no-such-user"; - UnitFileInstallInfo i = {name, path, user}; - UnitFileInstallInfo i2 = {name, path, NULL}; + path[] = "/run/systemd/system/name.service"; + UnitFileInstallInfo i = { .name = name, .path = path, }; + UnitFileInstallInfo i2 = { .name= name, .path = path, }; char name3[] = "name@inst.service", path3[] = "/run/systemd/system/name.service"; - UnitFileInstallInfo i3 = {name3, path3, user}; - UnitFileInstallInfo i4 = {name3, path3, NULL}; + UnitFileInstallInfo i3 = { .name = name3, .path = path3, }; + UnitFileInstallInfo i4 = { .name = name3, .path = path3, }; - _cleanup_free_ char *mid, *bid, *host; + _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL; assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid); assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid); assert_se((host = gethostname_malloc())); + assert_se((user = getusername_malloc())); + assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0); #define expect(src, pattern, result) \ do { \ _cleanup_free_ char *t = NULL; \ _cleanup_free_ char \ *d1 = strdup(i.name), \ - *d2 = strdup(i.path), \ - *d3 = strdup(i.user); \ + *d2 = strdup(i.path); \ assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \ memzero(i.name, strlen(i.name)); \ memzero(i.path, strlen(i.path)); \ - memzero(i.user, strlen(i.user)); \ - assert_se(d1 && d2 && d3); \ + assert_se(d1 && d2); \ if (result) { \ printf("%s\n", t); \ - assert_se(streq(t, result)); \ - } else assert_se(t == NULL); \ + assert_se(streq(t, result)); \ + } else assert_se(t == NULL); \ strcpy(i.name, d1); \ strcpy(i.path, d2); \ - strcpy(i.user, d3); \ - } while(false) - - assert_se(setenv("USER", "root", 1) == 0); + } while (false) expect(i, "%n", "name.service"); expect(i, "%N", "name"); expect(i, "%p", "name"); expect(i, "%i", ""); - expect(i, "%u", "xxxx-no-such-user"); - - DISABLE_WARNING_NONNULL; - expect(i, "%U", NULL); - REENABLE_WARNING; + expect(i, "%u", user); + expect(i, "%U", uid); expect(i, "%m", mid); expect(i, "%b", bid); expect(i, "%H", host); - expect(i2, "%u", "root"); - expect(i2, "%U", "0"); + expect(i2, "%u", user); + expect(i2, "%U", uid); expect(i3, "%n", "name@inst.service"); expect(i3, "%N", "name@inst"); expect(i3, "%p", "name"); - expect(i3, "%u", "xxxx-no-such-user"); - - DISABLE_WARNING_NONNULL; - expect(i3, "%U", NULL); - REENABLE_WARNING; + expect(i3, "%u", user); + expect(i3, "%U", uid); expect(i3, "%m", mid); expect(i3, "%b", bid); expect(i3, "%H", host); - expect(i4, "%u", "root"); - expect(i4, "%U", "0"); + expect(i4, "%u", user); + expect(i4, "%U", uid); +} + +static uint64_t make_cap(int cap) { + return ((uint64_t) 1ULL << (uint64_t) cap); +} + +static void test_config_parse_capability_set(void) { + /* int config_parse_capability_set( + const char *unit, + 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; + uint64_t capability_bounding_set = 0; + + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "CAP_NET_RAW", + &capability_bounding_set, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set == make_cap(CAP_NET_RAW)); + + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "CAP_NET_ADMIN", + &capability_bounding_set, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); + + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "", + &capability_bounding_set, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set == UINT64_C(0)); + + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "~", + &capability_bounding_set, NULL); + assert_se(r >= 0); + assert_se(cap_test_all(capability_bounding_set)); + + capability_bounding_set = 0; + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, " 'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage", + &capability_bounding_set, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); +} + +static void test_config_parse_rlimit(void) { + struct rlimit * rl[_RLIMIT_MAX] = {}; + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 66); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + + rl[RLIMIT_NOFILE]->rlim_cur = 10; + rl[RLIMIT_NOFILE]->rlim_max = 20; + + /* Invalid values don't change rl */ + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); + + rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 56); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 57); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 40); + assert_se(rl[RLIMIT_CPU]->rlim_max == 60); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 2); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); + assert_se(rl[RLIMIT_RTTIME]->rlim_max == 60); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_max == 123 * USEC_PER_SEC); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + rl[RLIMIT_RTTIME] = mfree(rl[RLIMIT_RTTIME]); +} + +static void test_config_parse_pass_environ(void) { + /* int config_parse_pass_environ( + const char *unit, + 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; + _cleanup_strv_free_ char **passenv = NULL; + + r = config_parse_pass_environ(NULL, "fake", 1, "section", 1, + "PassEnvironment", 0, "A B", + &passenv, NULL); + assert_se(r >= 0); + assert_se(strv_length(passenv) == 2); + assert_se(streq(passenv[0], "A")); + assert_se(streq(passenv[1], "B")); + + r = config_parse_pass_environ(NULL, "fake", 1, "section", 1, + "PassEnvironment", 0, "", + &passenv, NULL); + assert_se(r >= 0); + assert_se(strv_isempty(passenv)); + + r = config_parse_pass_environ(NULL, "fake", 1, "section", 1, + "PassEnvironment", 0, "'invalid name' 'normal_name' A=1 \\", + &passenv, NULL); + assert_se(r >= 0); + assert_se(strv_length(passenv) == 1); + assert_se(streq(passenv[0], "normal_name")); + } int main(int argc, char *argv[]) { + _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL; int r; log_parse_environment(); log_open(); + assert_se(runtime_dir = setup_fake_runtime_dir()); + r = test_unit_file_get_set(); test_config_parse_exec(); + test_config_parse_capability_set(); + test_config_parse_rlimit(); + test_config_parse_pass_environ(); test_load_env_file_1(); test_load_env_file_2(); test_load_env_file_3(); diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index e5405fb7f3..2fd83f321c 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,21 +19,25 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <pwd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <pwd.h> +#include "alloc-util.h" +#include "glob-util.h" +#include "hostname-util.h" +#include "macro.h" #include "manager.h" -#include "unit.h" +#include "path-util.h" +#include "specifier.h" +#include "string-util.h" +#include "test-helper.h" #include "unit-name.h" #include "unit-printf.h" -#include "specifier.h" +#include "unit.h" +#include "user-util.h" #include "util.h" -#include "macro.h" -#include "path-util.h" -#include "test-helper.h" -#include "hostname-util.h" static void test_unit_name_is_valid(void) { assert_se(unit_name_is_valid("foo.service", UNIT_NAME_ANY)); @@ -63,26 +65,26 @@ static void test_unit_name_is_valid(void) { assert_se(!unit_name_is_valid("@piep.service", UNIT_NAME_ANY)); } -static void test_u_n_r_i_one(const char *pattern, const char *repl, const char *expected, int ret) { +static void test_unit_name_replace_instance_one(const char *pattern, const char *repl, const char *expected, int ret) { _cleanup_free_ char *t = NULL; assert_se(unit_name_replace_instance(pattern, repl, &t) == ret); puts(strna(t)); assert_se(streq_ptr(t, expected)); } -static void test_u_n_r_i(void) { +static void test_unit_name_replace_instance(void) { puts("-------------------------------------------------"); - test_u_n_r_i_one("foo@.service", "waldo", "foo@waldo.service", 0); - test_u_n_r_i_one("foo@xyz.service", "waldo", "foo@waldo.service", 0); - test_u_n_r_i_one("xyz", "waldo", NULL, -EINVAL); - test_u_n_r_i_one("", "waldo", NULL, -EINVAL); - test_u_n_r_i_one("foo.service", "waldo", NULL, -EINVAL); - test_u_n_r_i_one(".service", "waldo", NULL, -EINVAL); - test_u_n_r_i_one("foo@", "waldo", NULL, -EINVAL); - test_u_n_r_i_one("@bar", "waldo", NULL, -EINVAL); + test_unit_name_replace_instance_one("foo@.service", "waldo", "foo@waldo.service", 0); + test_unit_name_replace_instance_one("foo@xyz.service", "waldo", "foo@waldo.service", 0); + test_unit_name_replace_instance_one("xyz", "waldo", NULL, -EINVAL); + test_unit_name_replace_instance_one("", "waldo", NULL, -EINVAL); + test_unit_name_replace_instance_one("foo.service", "waldo", NULL, -EINVAL); + test_unit_name_replace_instance_one(".service", "waldo", NULL, -EINVAL); + test_unit_name_replace_instance_one("foo@", "waldo", NULL, -EINVAL); + test_unit_name_replace_instance_one("@bar", "waldo", NULL, -EINVAL); } -static void test_u_n_f_p_one(const char *path, const char *suffix, const char *expected, int ret) { +static void test_unit_name_from_path_one(const char *path, const char *suffix, const char *expected, int ret) { _cleanup_free_ char *t = NULL; assert_se(unit_name_from_path(path, suffix, &t) == ret); @@ -97,19 +99,19 @@ static void test_u_n_f_p_one(const char *path, const char *suffix, const char *e } } -static void test_u_n_f_p(void) { +static void test_unit_name_from_path(void) { puts("-------------------------------------------------"); - test_u_n_f_p_one("/waldo", ".mount", "waldo.mount", 0); - test_u_n_f_p_one("/waldo/quuix", ".mount", "waldo-quuix.mount", 0); - test_u_n_f_p_one("/waldo/quuix/", ".mount", "waldo-quuix.mount", 0); - test_u_n_f_p_one("", ".mount", "-.mount", 0); - test_u_n_f_p_one("/", ".mount", "-.mount", 0); - test_u_n_f_p_one("///", ".mount", "-.mount", 0); - test_u_n_f_p_one("/foo/../bar", ".mount", NULL, -EINVAL); - test_u_n_f_p_one("/foo/./bar", ".mount", NULL, -EINVAL); + test_unit_name_from_path_one("/waldo", ".mount", "waldo.mount", 0); + test_unit_name_from_path_one("/waldo/quuix", ".mount", "waldo-quuix.mount", 0); + test_unit_name_from_path_one("/waldo/quuix/", ".mount", "waldo-quuix.mount", 0); + test_unit_name_from_path_one("", ".mount", "-.mount", 0); + test_unit_name_from_path_one("/", ".mount", "-.mount", 0); + test_unit_name_from_path_one("///", ".mount", "-.mount", 0); + test_unit_name_from_path_one("/foo/../bar", ".mount", NULL, -EINVAL); + test_unit_name_from_path_one("/foo/./bar", ".mount", NULL, -EINVAL); } -static void test_u_n_f_p_i_one(const char *pattern, const char *path, const char *suffix, const char *expected, int ret) { +static void test_unit_name_from_path_instance_one(const char *pattern, const char *path, const char *suffix, const char *expected, int ret) { _cleanup_free_ char *t = NULL; assert_se(unit_name_from_path_instance(pattern, path, suffix, &t) == ret); @@ -125,65 +127,71 @@ static void test_u_n_f_p_i_one(const char *pattern, const char *path, const char } } -static void test_u_n_f_p_i(void) { +static void test_unit_name_from_path_instance(void) { puts("-------------------------------------------------"); - test_u_n_f_p_i_one("waldo", "/waldo", ".mount", "waldo@waldo.mount", 0); - test_u_n_f_p_i_one("waldo", "/waldo////quuix////", ".mount", "waldo@waldo-quuix.mount", 0); - test_u_n_f_p_i_one("waldo", "/", ".mount", "waldo@-.mount", 0); - test_u_n_f_p_i_one("waldo", "", ".mount", "waldo@-.mount", 0); - test_u_n_f_p_i_one("waldo", "///", ".mount", "waldo@-.mount", 0); - test_u_n_f_p_i_one("waldo", "..", ".mount", NULL, -EINVAL); - test_u_n_f_p_i_one("waldo", "/foo", ".waldi", NULL, -EINVAL); - test_u_n_f_p_i_one("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount", 0); + test_unit_name_from_path_instance_one("waldo", "/waldo", ".mount", "waldo@waldo.mount", 0); + test_unit_name_from_path_instance_one("waldo", "/waldo////quuix////", ".mount", "waldo@waldo-quuix.mount", 0); + test_unit_name_from_path_instance_one("waldo", "/", ".mount", "waldo@-.mount", 0); + test_unit_name_from_path_instance_one("waldo", "", ".mount", "waldo@-.mount", 0); + test_unit_name_from_path_instance_one("waldo", "///", ".mount", "waldo@-.mount", 0); + test_unit_name_from_path_instance_one("waldo", "..", ".mount", NULL, -EINVAL); + test_unit_name_from_path_instance_one("waldo", "/foo", ".waldi", NULL, -EINVAL); + test_unit_name_from_path_instance_one("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount", 0); } -static void test_u_n_t_p_one(const char *unit, const char *path, int ret) { +static void test_unit_name_to_path_one(const char *unit, const char *path, int ret) { _cleanup_free_ char *p = NULL; assert_se(unit_name_to_path(unit, &p) == ret); assert_se(streq_ptr(path, p)); } -static void test_u_n_t_p(void) { - test_u_n_t_p_one("home.mount", "/home", 0); - test_u_n_t_p_one("home-lennart.mount", "/home/lennart", 0); - test_u_n_t_p_one("home-lennart-.mount", NULL, -EINVAL); - test_u_n_t_p_one("-home-lennart.mount", NULL, -EINVAL); - test_u_n_t_p_one("-home--lennart.mount", NULL, -EINVAL); - test_u_n_t_p_one("home-..-lennart.mount", NULL, -EINVAL); - test_u_n_t_p_one("", NULL, -EINVAL); - test_u_n_t_p_one("home/foo", NULL, -EINVAL); +static void test_unit_name_to_path(void) { + test_unit_name_to_path_one("home.mount", "/home", 0); + test_unit_name_to_path_one("home-lennart.mount", "/home/lennart", 0); + test_unit_name_to_path_one("home-lennart-.mount", NULL, -EINVAL); + test_unit_name_to_path_one("-home-lennart.mount", NULL, -EINVAL); + test_unit_name_to_path_one("-home--lennart.mount", NULL, -EINVAL); + test_unit_name_to_path_one("home-..-lennart.mount", NULL, -EINVAL); + test_unit_name_to_path_one("", NULL, -EINVAL); + test_unit_name_to_path_one("home/foo", NULL, -EINVAL); } -static void test_u_n_m_one(const char *pattern, const char *expect, int ret) { +static void test_unit_name_mangle_one(UnitNameMangle allow_globs, const char *pattern, const char *expect, int ret) { _cleanup_free_ char *t = NULL; - assert_se(unit_name_mangle(pattern, UNIT_NAME_NOGLOB, &t) == ret); + assert_se(unit_name_mangle(pattern, allow_globs, &t) == ret); puts(strna(t)); assert_se(streq_ptr(t, expect)); if (t) { _cleanup_free_ char *k = NULL; - assert_se(unit_name_is_valid(t, UNIT_NAME_ANY)); + assert_se(unit_name_is_valid(t, UNIT_NAME_ANY) || + (allow_globs == UNIT_NAME_GLOB && string_is_glob(t))); - assert_se(unit_name_mangle(t, UNIT_NAME_NOGLOB, &k) == 0); + assert_se(unit_name_mangle(t, allow_globs, &k) == 0); assert_se(streq_ptr(t, k)); } } -static void test_u_n_m(void) { +static void test_unit_name_mangle(void) { puts("-------------------------------------------------"); - test_u_n_m_one("foo.service", "foo.service", 0); - test_u_n_m_one("/home", "home.mount", 1); - test_u_n_m_one("/dev/sda", "dev-sda.device", 1); - test_u_n_m_one("üxknürz.service", "\\xc3\\xbcxkn\\xc3\\xbcrz.service", 1); - test_u_n_m_one("foobar-meh...waldi.service", "foobar-meh...waldi.service", 0); - test_u_n_m_one("_____####----.....service", "_____\\x23\\x23\\x23\\x23----.....service", 1); - test_u_n_m_one("_____##@;;;,,,##----.....service", "_____\\x23\\x23@\\x3b\\x3b\\x3b\\x2c\\x2c\\x2c\\x23\\x23----.....service", 1); - test_u_n_m_one("xxx@@@@/////\\\\\\\\\\yyy.service", "xxx@@@@-----\\\\\\\\\\yyy.service", 1); - test_u_n_m_one("", NULL, -EINVAL); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "foo.service", "foo.service", 0); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "/home", "home.mount", 1); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "/dev/sda", "dev-sda.device", 1); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "üxknürz.service", "\\xc3\\xbcxkn\\xc3\\xbcrz.service", 1); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "foobar-meh...waldi.service", "foobar-meh...waldi.service", 0); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "_____####----.....service", "_____\\x23\\x23\\x23\\x23----.....service", 1); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "_____##@;;;,,,##----.....service", "_____\\x23\\x23@\\x3b\\x3b\\x3b\\x2c\\x2c\\x2c\\x23\\x23----.....service", 1); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "xxx@@@@/////\\\\\\\\\\yyy.service", "xxx@@@@-----\\\\\\\\\\yyy.service", 1); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "", NULL, -EINVAL); + + test_unit_name_mangle_one(UNIT_NAME_GLOB, "foo.service", "foo.service", 0); + test_unit_name_mangle_one(UNIT_NAME_GLOB, "foo", "foo.service", 1); + test_unit_name_mangle_one(UNIT_NAME_GLOB, "foo*", "foo*", 0); + test_unit_name_mangle_one(UNIT_NAME_GLOB, "ü*", "\\xc3\\xbc*", 1); } static int test_unit_printf(void) { @@ -191,17 +199,17 @@ static int test_unit_printf(void) { Unit *u, *u2; int r; - _cleanup_free_ char *mid, *bid, *host, *root_uid; - struct passwd *root; + _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL, *shell = NULL, *home = NULL; assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid); assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid); - assert_se((host = gethostname_malloc())); - - assert_se((root = getpwnam("root"))); - assert_se(asprintf(&root_uid, "%d", (int) root->pw_uid) > 0); + assert_se(host = gethostname_malloc()); + assert_se(user = getusername_malloc()); + assert_se(asprintf(&uid, UID_FMT, getuid())); + assert_se(get_home_dir(&home) >= 0); + assert_se(get_shell(&shell) >= 0); - r = manager_new(MANAGER_USER, true, &m); + r = manager_new(UNIT_FILE_USER, true, &m); if (r == -EPERM || r == -EACCES || r == -EADDRINUSE) { puts("manager_new: Permission denied. Skipping test."); return EXIT_TEST_SKIP; @@ -220,8 +228,6 @@ static int test_unit_printf(void) { assert_se(streq(t, expected)); \ } - assert_se(setenv("USER", "root", 1) == 0); - assert_se(setenv("HOME", "/root", 1) == 0); assert_se(setenv("XDG_RUNTIME_DIR", "/run/user/1/", 1) == 0); assert_se(u = unit_new(m, sizeof(Service))); @@ -240,9 +246,9 @@ static int test_unit_printf(void) { expect(u, "%p", "blah"); expect(u, "%P", "blah"); expect(u, "%i", ""); - expect(u, "%u", root->pw_name); - expect(u, "%U", root_uid); - expect(u, "%h", root->pw_dir); + expect(u, "%u", user); + expect(u, "%U", uid); + expect(u, "%h", home); expect(u, "%m", mid); expect(u, "%b", bid); expect(u, "%H", host); @@ -260,9 +266,9 @@ static int test_unit_printf(void) { expect(u2, "%P", "blah"); expect(u2, "%i", "foo-foo"); expect(u2, "%I", "foo/foo"); - expect(u2, "%u", root->pw_name); - expect(u2, "%U", root_uid); - expect(u2, "%h", root->pw_dir); + expect(u2, "%u", user); + expect(u2, "%U", uid); + expect(u2, "%h", home); expect(u2, "%m", mid); expect(u2, "%b", bid); expect(u2, "%H", host); @@ -459,11 +465,11 @@ static void test_unit_name_path_unescape(void) { int main(int argc, char* argv[]) { int rc = 0; test_unit_name_is_valid(); - test_u_n_r_i(); - test_u_n_f_p(); - test_u_n_f_p_i(); - test_u_n_m(); - test_u_n_t_p(); + test_unit_name_replace_instance(); + test_unit_name_from_path(); + test_unit_name_from_path_instance(); + test_unit_name_mangle(); + test_unit_name_to_path(); TEST_REQ_RUNNING_SYSTEMD(rc = test_unit_printf()); test_unit_instance_is_valid(); test_unit_prefix_is_valid(); diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c new file mode 100644 index 0000000000..2a344a9f93 --- /dev/null +++ b/src/test/test-user-util.c @@ -0,0 +1,166 @@ +/*** + 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 "alloc-util.h" +#include "macro.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" + +static void test_uid_to_name_one(uid_t uid, const char *name) { + _cleanup_free_ char *t = NULL; + + assert_se(t = uid_to_name(uid)); + assert_se(streq_ptr(t, name)); +} + +static void test_gid_to_name_one(gid_t gid, const char *name) { + _cleanup_free_ char *t = NULL; + + assert_se(t = gid_to_name(gid)); + assert_se(streq_ptr(t, name)); +} + +static void test_parse_uid(void) { + int r; + uid_t uid; + + r = parse_uid("100", &uid); + assert_se(r == 0); + assert_se(uid == 100); + + r = parse_uid("65535", &uid); + assert_se(r == -ENXIO); + + r = parse_uid("asdsdas", &uid); + assert_se(r == -EINVAL); +} + +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_valid_user_group_name(void) { + assert_se(!valid_user_group_name(NULL)); + assert_se(!valid_user_group_name("")); + assert_se(!valid_user_group_name("1")); + assert_se(!valid_user_group_name("65535")); + assert_se(!valid_user_group_name("-1")); + assert_se(!valid_user_group_name("-kkk")); + assert_se(!valid_user_group_name("rööt")); + assert_se(!valid_user_group_name(".")); + assert_se(!valid_user_group_name("eff.eff")); + assert_se(!valid_user_group_name("foo\nbar")); + assert_se(!valid_user_group_name("0123456789012345678901234567890123456789")); + assert_se(!valid_user_group_name_or_id("aaa:bbb")); + + assert_se(valid_user_group_name("root")); + assert_se(valid_user_group_name("lennart")); + assert_se(valid_user_group_name("LENNART")); + assert_se(valid_user_group_name("_kkk")); + assert_se(valid_user_group_name("kkk-")); + assert_se(valid_user_group_name("kk-k")); + + assert_se(valid_user_group_name("some5")); + assert_se(!valid_user_group_name("5some")); + assert_se(valid_user_group_name("INNER5NUMBER")); +} + +static void test_valid_user_group_name_or_id(void) { + assert_se(!valid_user_group_name_or_id(NULL)); + assert_se(!valid_user_group_name_or_id("")); + assert_se(valid_user_group_name_or_id("0")); + assert_se(valid_user_group_name_or_id("1")); + assert_se(valid_user_group_name_or_id("65534")); + assert_se(!valid_user_group_name_or_id("65535")); + assert_se(valid_user_group_name_or_id("65536")); + assert_se(!valid_user_group_name_or_id("-1")); + assert_se(!valid_user_group_name_or_id("-kkk")); + assert_se(!valid_user_group_name_or_id("rööt")); + assert_se(!valid_user_group_name_or_id(".")); + assert_se(!valid_user_group_name_or_id("eff.eff")); + assert_se(!valid_user_group_name_or_id("foo\nbar")); + assert_se(!valid_user_group_name_or_id("0123456789012345678901234567890123456789")); + assert_se(!valid_user_group_name_or_id("aaa:bbb")); + + assert_se(valid_user_group_name_or_id("root")); + assert_se(valid_user_group_name_or_id("lennart")); + assert_se(valid_user_group_name_or_id("LENNART")); + assert_se(valid_user_group_name_or_id("_kkk")); + assert_se(valid_user_group_name_or_id("kkk-")); + assert_se(valid_user_group_name_or_id("kk-k")); + + assert_se(valid_user_group_name_or_id("some5")); + assert_se(!valid_user_group_name_or_id("5some")); + assert_se(valid_user_group_name_or_id("INNER5NUMBER")); +} + +static void test_valid_gecos(void) { + + assert_se(!valid_gecos(NULL)); + assert_se(valid_gecos("")); + assert_se(valid_gecos("test")); + assert_se(valid_gecos("Ümläüt")); + assert_se(!valid_gecos("In\nvalid")); + assert_se(!valid_gecos("In:valid")); +} + +static void test_valid_home(void) { + + assert_se(!valid_home(NULL)); + assert_se(!valid_home("")); + assert_se(!valid_home(".")); + assert_se(!valid_home("/home/..")); + assert_se(!valid_home("/home/../")); + assert_se(!valid_home("/home\n/foo")); + assert_se(!valid_home("./piep")); + assert_se(!valid_home("piep")); + assert_se(!valid_home("/home/user:lennart")); + + assert_se(valid_home("/")); + assert_se(valid_home("/home")); + assert_se(valid_home("/home/foo")); +} + +int main(int argc, char*argv[]) { + + test_uid_to_name_one(0, "root"); + test_uid_to_name_one(0xFFFF, "65535"); + test_uid_to_name_one(0xFFFFFFFF, "4294967295"); + + test_gid_to_name_one(0, "root"); + test_gid_to_name_one(TTY_GID, "tty"); + test_gid_to_name_one(0xFFFF, "65535"); + test_gid_to_name_one(0xFFFFFFFF, "4294967295"); + + test_parse_uid(); + test_uid_ptr(); + + test_valid_user_group_name(); + test_valid_user_group_name_or_id(); + test_valid_gecos(); + test_valid_home(); + + return 0; +} diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c index 346f8524c6..1ce5a5a24d 100644 --- a/src/test/test-utf8.c +++ b/src/test/test-utf8.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,6 +17,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" +#include "string-util.h" #include "utf8.h" #include "util.h" diff --git a/src/test/test-util.c b/src/test/test-util.c index 7906c4d7bb..1b5cba86c1 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,31 +18,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <locale.h> #include <errno.h> -#include <signal.h> -#include <math.h> +#include <string.h> #include <sys/wait.h> +#include <unistd.h> -#include "util.h" -#include "mkdir.h" -#include "rm-rf.h" -#include "strv.h" #include "def.h" #include "fileio.h" -#include "conf-parser.h" -#include "virt.h" -#include "process-util.h" -#include "hostname-util.h" -#include "signal-util.h" - -static void test_streq_ptr(void) { - assert_se(streq_ptr(NULL, NULL)); - assert_se(!streq_ptr("abc", "cdef")); -} +#include "fs-util.h" +#include "parse-util.h" +#include "raw-clone.h" +#include "rm-rf.h" +#include "string-util.h" +#include "util.h" static void test_align_power2(void) { unsigned long i, p2; @@ -136,19 +122,6 @@ static void test_container_of(void) { v1) == &myval); } -static void test_alloca(void) { - static const uint8_t zero[997] = { }; - char *t; - - t = alloca_align(17, 512); - assert_se(!((uintptr_t)t & 0xff)); - memzero(t, 17); - - t = alloca0_align(997, 1024); - assert_se(!((uintptr_t)t & 0x1ff)); - assert_se(!memcmp(t, zero, 997)); -} - static void test_div_round_up(void) { int div; @@ -182,723 +155,6 @@ static void test_div_round_up(void) { assert_se(0xfffffffdU / 10U + !!(0xfffffffdU % 10U) == 429496730U); } -static void test_first_word(void) { - assert_se(first_word("Hello", "")); - assert_se(first_word("Hello", "Hello")); - assert_se(first_word("Hello world", "Hello")); - assert_se(first_word("Hello\tworld", "Hello")); - assert_se(first_word("Hello\nworld", "Hello")); - assert_se(first_word("Hello\rworld", "Hello")); - assert_se(first_word("Hello ", "Hello")); - - assert_se(!first_word("Hello", "Hellooo")); - assert_se(!first_word("Hello", "xxxxx")); - assert_se(!first_word("Hellooo", "Hello")); -} - -static void test_close_many(void) { - int fds[3]; - char name0[] = "/tmp/test-close-many.XXXXXX"; - char name1[] = "/tmp/test-close-many.XXXXXX"; - char name2[] = "/tmp/test-close-many.XXXXXX"; - - fds[0] = mkostemp_safe(name0, O_RDWR|O_CLOEXEC); - fds[1] = mkostemp_safe(name1, O_RDWR|O_CLOEXEC); - fds[2] = mkostemp_safe(name2, O_RDWR|O_CLOEXEC); - - close_many(fds, 2); - - assert_se(fcntl(fds[0], F_GETFD) == -1); - assert_se(fcntl(fds[1], F_GETFD) == -1); - assert_se(fcntl(fds[2], F_GETFD) >= 0); - - safe_close(fds[2]); - - unlink(name0); - unlink(name1); - unlink(name2); -} - -static void test_parse_boolean(void) { - assert_se(parse_boolean("1") == 1); - assert_se(parse_boolean("y") == 1); - assert_se(parse_boolean("Y") == 1); - assert_se(parse_boolean("yes") == 1); - assert_se(parse_boolean("YES") == 1); - assert_se(parse_boolean("true") == 1); - assert_se(parse_boolean("TRUE") == 1); - assert_se(parse_boolean("on") == 1); - assert_se(parse_boolean("ON") == 1); - - assert_se(parse_boolean("0") == 0); - assert_se(parse_boolean("n") == 0); - assert_se(parse_boolean("N") == 0); - assert_se(parse_boolean("no") == 0); - assert_se(parse_boolean("NO") == 0); - assert_se(parse_boolean("false") == 0); - assert_se(parse_boolean("FALSE") == 0); - assert_se(parse_boolean("off") == 0); - assert_se(parse_boolean("OFF") == 0); - - assert_se(parse_boolean("garbage") < 0); - assert_se(parse_boolean("") < 0); - assert_se(parse_boolean("full") < 0); -} - -static void test_parse_pid(void) { - int r; - pid_t pid; - - r = parse_pid("100", &pid); - assert_se(r == 0); - assert_se(pid == 100); - - r = parse_pid("0x7FFFFFFF", &pid); - assert_se(r == 0); - assert_se(pid == 2147483647); - - pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ - r = parse_pid("0", &pid); - assert_se(r == -ERANGE); - assert_se(pid == 65); - - pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ - r = parse_pid("-100", &pid); - assert_se(r == -ERANGE); - assert_se(pid == 65); - - pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ - r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid); - assert_se(r == -ERANGE); - assert_se(pid == 65); -} - -static void test_parse_uid(void) { - int r; - uid_t uid; - - r = parse_uid("100", &uid); - assert_se(r == 0); - assert_se(uid == 100); -} - -static void test_safe_atolli(void) { - int r; - long long l; - - r = safe_atolli("12345", &l); - assert_se(r == 0); - assert_se(l == 12345); - - r = safe_atolli("junk", &l); - assert_se(r == -EINVAL); -} - -static void test_safe_atod(void) { - int r; - double d; - char *e; - - r = safe_atod("junk", &d); - assert_se(r == -EINVAL); - - r = safe_atod("0.2244", &d); - assert_se(r == 0); - assert_se(fabs(d - 0.2244) < 0.000001); - - r = safe_atod("0,5", &d); - assert_se(r == -EINVAL); - - errno = 0; - strtod("0,5", &e); - assert_se(*e == ','); - - /* Check if this really is locale independent */ - if (setlocale(LC_NUMERIC, "de_DE.utf8")) { - - r = safe_atod("0.2244", &d); - assert_se(r == 0); - assert_se(fabs(d - 0.2244) < 0.000001); - - r = safe_atod("0,5", &d); - assert_se(r == -EINVAL); - - errno = 0; - assert_se(fabs(strtod("0,5", &e) - 0.5) < 0.00001); - } - - /* And check again, reset */ - assert_se(setlocale(LC_NUMERIC, "C")); - - r = safe_atod("0.2244", &d); - assert_se(r == 0); - assert_se(fabs(d - 0.2244) < 0.000001); - - r = safe_atod("0,5", &d); - assert_se(r == -EINVAL); - - errno = 0; - strtod("0,5", &e); - assert_se(*e == ','); -} - -static void test_strappend(void) { - _cleanup_free_ char *t1, *t2, *t3, *t4; - - t1 = strappend(NULL, NULL); - assert_se(streq(t1, "")); - - t2 = strappend(NULL, "suf"); - assert_se(streq(t2, "suf")); - - t3 = strappend("pre", NULL); - assert_se(streq(t3, "pre")); - - t4 = strappend("pre", "suf"); - assert_se(streq(t4, "presuf")); -} - -static void test_strstrip(void) { - char *r; - char input[] = " hello, waldo. "; - - r = strstrip(input); - assert_se(streq(r, "hello, waldo.")); -} - -static void test_delete_chars(void) { - char *r; - char input[] = " hello, waldo. abc"; - - r = delete_chars(input, WHITESPACE); - assert_se(streq(r, "hello,waldo.abc")); -} - -static void test_in_charset(void) { - assert_se(in_charset("dddaaabbbcccc", "abcd")); - assert_se(!in_charset("dddaaabbbcccc", "abc f")); -} - -static void test_hexchar(void) { - assert_se(hexchar(0xa) == 'a'); - assert_se(hexchar(0x0) == '0'); -} - -static void test_unhexchar(void) { - assert_se(unhexchar('a') == 0xA); - assert_se(unhexchar('A') == 0xA); - assert_se(unhexchar('0') == 0x0); -} - -static void test_base32hexchar(void) { - assert_se(base32hexchar(0) == '0'); - assert_se(base32hexchar(9) == '9'); - assert_se(base32hexchar(10) == 'A'); - assert_se(base32hexchar(31) == 'V'); -} - -static void test_unbase32hexchar(void) { - assert_se(unbase32hexchar('0') == 0); - assert_se(unbase32hexchar('9') == 9); - assert_se(unbase32hexchar('A') == 10); - assert_se(unbase32hexchar('V') == 31); - assert_se(unbase32hexchar('=') == -EINVAL); -} - -static void test_base64char(void) { - assert_se(base64char(0) == 'A'); - assert_se(base64char(26) == 'a'); - assert_se(base64char(63) == '/'); -} - -static void test_unbase64char(void) { - assert_se(unbase64char('A') == 0); - assert_se(unbase64char('Z') == 25); - assert_se(unbase64char('a') == 26); - assert_se(unbase64char('z') == 51); - assert_se(unbase64char('0') == 52); - assert_se(unbase64char('9') == 61); - assert_se(unbase64char('+') == 62); - assert_se(unbase64char('/') == 63); - assert_se(unbase64char('=') == -EINVAL); -} - -static void test_octchar(void) { - assert_se(octchar(00) == '0'); - assert_se(octchar(07) == '7'); -} - -static void test_unoctchar(void) { - assert_se(unoctchar('0') == 00); - assert_se(unoctchar('7') == 07); -} - -static void test_decchar(void) { - assert_se(decchar(0) == '0'); - assert_se(decchar(9) == '9'); -} - -static void test_undecchar(void) { - assert_se(undecchar('0') == 0); - assert_se(undecchar('9') == 9); -} - -static void test_unhexmem(void) { - const char *hex = "efa214921"; - const char *hex_invalid = "efa214921o"; - _cleanup_free_ char *hex2 = NULL; - _cleanup_free_ void *mem = NULL; - size_t len; - - assert_se(unhexmem(hex, strlen(hex), &mem, &len) == 0); - assert_se(unhexmem(hex, strlen(hex) + 1, &mem, &len) == -EINVAL); - assert_se(unhexmem(hex_invalid, strlen(hex_invalid), &mem, &len) == -EINVAL); - - assert_se((hex2 = hexmem(mem, len))); - - free(mem); - - assert_se(memcmp(hex, hex2, strlen(hex)) == 0); - - free(hex2); - - assert_se(unhexmem(hex, strlen(hex) - 1, &mem, &len) == 0); - assert_se((hex2 = hexmem(mem, len))); - assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0); -} - -/* https://tools.ietf.org/html/rfc4648#section-10 */ -static void test_base32hexmem(void) { - char *b32; - - b32 = base32hexmem("", strlen(""), true); - assert_se(b32); - assert_se(streq(b32, "")); - free(b32); - - b32 = base32hexmem("f", strlen("f"), true); - assert_se(b32); - assert_se(streq(b32, "CO======")); - free(b32); - - b32 = base32hexmem("fo", strlen("fo"), true); - assert_se(b32); - assert_se(streq(b32, "CPNG====")); - free(b32); - - b32 = base32hexmem("foo", strlen("foo"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMU===")); - free(b32); - - b32 = base32hexmem("foob", strlen("foob"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMUOG=")); - free(b32); - - b32 = base32hexmem("fooba", strlen("fooba"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1")); - free(b32); - - b32 = base32hexmem("foobar", strlen("foobar"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1E8======")); - free(b32); - - b32 = base32hexmem("", strlen(""), false); - assert_se(b32); - assert_se(streq(b32, "")); - free(b32); - - b32 = base32hexmem("f", strlen("f"), false); - assert_se(b32); - assert_se(streq(b32, "CO")); - free(b32); - - b32 = base32hexmem("fo", strlen("fo"), false); - assert_se(b32); - assert_se(streq(b32, "CPNG")); - free(b32); - - b32 = base32hexmem("foo", strlen("foo"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMU")); - free(b32); - - b32 = base32hexmem("foob", strlen("foob"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMUOG")); - free(b32); - - b32 = base32hexmem("fooba", strlen("fooba"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1")); - free(b32); - - b32 = base32hexmem("foobar", strlen("foobar"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1E8")); - free(b32); -} - -static void test_unbase32hexmem(void) { - void *mem; - size_t len; - - assert_se(unbase32hexmem("", strlen(""), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "")); - free(mem); - - assert_se(unbase32hexmem("CO======", strlen("CO======"), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "f")); - free(mem); - - assert_se(unbase32hexmem("CPNG====", strlen("CPNG===="), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fo")); - free(mem); - - assert_se(unbase32hexmem("CPNMU===", strlen("CPNMU==="), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foo")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foob")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fooba")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foobar")); - free(mem); - - assert_se(unbase32hexmem("A", strlen("A"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("A=======", strlen("A======="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAA=====", strlen("AAA====="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAA==", strlen("AAAAAA=="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AB======", strlen("AB======"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAB====", strlen("AAAB===="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAB===", strlen("AAAAB==="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAAB=", strlen("AAAAAAB="), true, &mem, &len) == -EINVAL); - - assert_se(unbase32hexmem("", strlen(""), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "")); - free(mem); - - assert_se(unbase32hexmem("CO", strlen("CO"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "f")); - free(mem); - - assert_se(unbase32hexmem("CPNG", strlen("CPNG"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fo")); - free(mem); - - assert_se(unbase32hexmem("CPNMU", strlen("CPNMU"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foo")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOG", strlen("CPNMUOG"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foob")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fooba")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1E8", strlen("CPNMUOJ1E8"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foobar")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAA", strlen("AAA"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAA", strlen("AAAAAA"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AB", strlen("AB"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAB", strlen("AAAB"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAB", strlen("AAAAB"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAAB", strlen("AAAAAAB"), false, &mem, &len) == -EINVAL); -} - -/* https://tools.ietf.org/html/rfc4648#section-10 */ -static void test_base64mem(void) { - char *b64; - - b64 = base64mem("", strlen("")); - assert_se(b64); - assert_se(streq(b64, "")); - free(b64); - - b64 = base64mem("f", strlen("f")); - assert_se(b64); - assert_se(streq(b64, "Zg==")); - free(b64); - - b64 = base64mem("fo", strlen("fo")); - assert_se(b64); - assert_se(streq(b64, "Zm8=")); - free(b64); - - b64 = base64mem("foo", strlen("foo")); - assert_se(b64); - assert_se(streq(b64, "Zm9v")); - free(b64); - - b64 = base64mem("foob", strlen("foob")); - assert_se(b64); - assert_se(streq(b64, "Zm9vYg==")); - free(b64); - - b64 = base64mem("fooba", strlen("fooba")); - assert_se(b64); - assert_se(streq(b64, "Zm9vYmE=")); - free(b64); - - b64 = base64mem("foobar", strlen("foobar")); - assert_se(b64); - assert_se(streq(b64, "Zm9vYmFy")); - free(b64); -} - -static void test_unbase64mem(void) { - void *mem; - size_t len; - - assert_se(unbase64mem("", strlen(""), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "")); - free(mem); - - assert_se(unbase64mem("Zg==", strlen("Zg=="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "f")); - free(mem); - - assert_se(unbase64mem("Zm8=", strlen("Zm8="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fo")); - free(mem); - - assert_se(unbase64mem("Zm9v", strlen("Zm9v"), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foo")); - free(mem); - - assert_se(unbase64mem("Zm9vYg==", strlen("Zm9vYg=="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foob")); - free(mem); - - assert_se(unbase64mem("Zm9vYmE=", strlen("Zm9vYmE="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fooba")); - free(mem); - - assert_se(unbase64mem("Zm9vYmFy", strlen("Zm9vYmFy"), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foobar")); - free(mem); - - assert_se(unbase64mem("A", strlen("A"), &mem, &len) == -EINVAL); - assert_se(unbase64mem("A====", strlen("A===="), &mem, &len) == -EINVAL); - assert_se(unbase64mem("AAB==", strlen("AAB=="), &mem, &len) == -EINVAL); - assert_se(unbase64mem("AAAB=", strlen("AAAB="), &mem, &len) == -EINVAL); -} - -static void test_cescape(void) { - _cleanup_free_ char *escaped; - - assert_se(escaped = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313")); - assert_se(streq(escaped, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313")); -} - -static void test_cunescape(void) { - _cleanup_free_ char *unescaped; - - assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", 0, &unescaped) < 0); - assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00")); - free(unescaped); - unescaped = NULL; - - /* incomplete sequences */ - assert_se(cunescape("\\x0", 0, &unescaped) < 0); - assert_se(cunescape("\\x0", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\x0")); - free(unescaped); - unescaped = NULL; - - assert_se(cunescape("\\x", 0, &unescaped) < 0); - assert_se(cunescape("\\x", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\x")); - free(unescaped); - unescaped = NULL; - - assert_se(cunescape("\\", 0, &unescaped) < 0); - assert_se(cunescape("\\", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\")); - free(unescaped); - unescaped = NULL; - - assert_se(cunescape("\\11", 0, &unescaped) < 0); - assert_se(cunescape("\\11", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\11")); - free(unescaped); - unescaped = NULL; - - assert_se(cunescape("\\1", 0, &unescaped) < 0); - assert_se(cunescape("\\1", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\1")); - free(unescaped); - unescaped = NULL; - - assert_se(cunescape("\\u0000", 0, &unescaped) < 0); - assert_se(cunescape("\\u00DF\\U000000df\\u03a0\\U00000041", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "ßßΠA")); - free(unescaped); - unescaped = NULL; - - assert_se(cunescape("\\073", 0, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, ";")); -} - -static void test_foreach_word(void) { - const char *word, *state; - size_t l; - int i = 0; - const char test[] = "test abc d\te f "; - const char * const expected[] = { - "test", - "abc", - "d", - "e", - "f", - "", - NULL - }; - - FOREACH_WORD(word, l, test, state) - assert_se(strneq(expected[i++], word, l)); -} - -static void check(const char *test, char** expected, bool trailing) { - const char *word, *state; - size_t l; - int i = 0; - - printf("<<<%s>>>\n", test); - FOREACH_WORD_QUOTED(word, l, test, state) { - _cleanup_free_ char *t = NULL; - - assert_se(t = strndup(word, l)); - assert_se(strneq(expected[i++], word, l)); - printf("<%s>\n", t); - } - 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_memdup_multiply(void) { - int org[] = {1, 2, 3}; - int *dup; - - dup = (int*)memdup_multiply(org, sizeof(int), 3); - - assert_se(dup); - assert_se(dup[0] == 1); - assert_se(dup[1] == 2); - assert_se(dup[2] == 3); - free(dup); -} - -static void test_hostname_is_valid(void) { - assert_se(hostname_is_valid("foobar")); - assert_se(hostname_is_valid("foobar.com")); - assert_se(!hostname_is_valid("fööbar")); - assert_se(!hostname_is_valid("")); - assert_se(!hostname_is_valid(".")); - assert_se(!hostname_is_valid("..")); - assert_se(!hostname_is_valid("foobar.")); - assert_se(!hostname_is_valid(".foobar")); - assert_se(!hostname_is_valid("foo..bar")); - assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); -} - -static void test_read_hostname_config(void) { - char path[] = "/tmp/hostname.XXXXXX"; - char *hostname; - int fd; - - fd = mkostemp_safe(path, O_RDWR|O_CLOEXEC); - assert(fd > 0); - close(fd); - - /* simple hostname */ - write_string_file(path, "foo", WRITE_STRING_FILE_CREATE); - assert_se(read_hostname_config(path, &hostname) == 0); - assert_se(streq(hostname, "foo")); - free(hostname); - hostname = NULL; - - /* with comment */ - write_string_file(path, "# comment\nfoo", WRITE_STRING_FILE_CREATE); - assert_se(read_hostname_config(path, &hostname) == 0); - assert_se(hostname); - assert_se(streq(hostname, "foo")); - free(hostname); - hostname = NULL; - - /* with comment and extra whitespace */ - write_string_file(path, "# comment\n\n foo ", WRITE_STRING_FILE_CREATE); - assert_se(read_hostname_config(path, &hostname) == 0); - assert_se(hostname); - assert_se(streq(hostname, "foo")); - free(hostname); - hostname = NULL; - - /* cleans up name */ - write_string_file(path, "!foo/bar.com", WRITE_STRING_FILE_CREATE); - assert_se(read_hostname_config(path, &hostname) == 0); - assert_se(hostname); - assert_se(streq(hostname, "foobar.com")); - free(hostname); - hostname = NULL; - - /* no value set */ - hostname = (char*) 0x1234; - write_string_file(path, "# nothing here\n", WRITE_STRING_FILE_CREATE); - assert_se(read_hostname_config(path, &hostname) == -ENOENT); - assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */ - - /* nonexisting file */ - assert_se(read_hostname_config("/non/existing", &hostname) == -ENOENT); - assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */ - - unlink(path); -} - static void test_u64log2(void) { assert_se(u64log2(0) == 0); assert_se(u64log2(8) == 3); @@ -918,163 +174,6 @@ static void test_protect_errno(void) { assert_se(errno == 12); } -static void test_parse_size(void) { - off_t bytes; - - assert_se(parse_size("111", 1024, &bytes) == 0); - assert_se(bytes == 111); - - assert_se(parse_size("111.4", 1024, &bytes) == 0); - assert_se(bytes == 111); - - assert_se(parse_size(" 112 B", 1024, &bytes) == 0); - assert_se(bytes == 112); - - assert_se(parse_size(" 112.6 B", 1024, &bytes) == 0); - assert_se(bytes == 112); - - assert_se(parse_size("3.5 K", 1024, &bytes) == 0); - assert_se(bytes == 3*1024 + 512); - - assert_se(parse_size("3. K", 1024, &bytes) == 0); - assert_se(bytes == 3*1024); - - assert_se(parse_size("3.0 K", 1024, &bytes) == 0); - assert_se(bytes == 3*1024); - - assert_se(parse_size("3. 0 K", 1024, &bytes) == -EINVAL); - - assert_se(parse_size(" 4 M 11.5K", 1024, &bytes) == 0); - assert_se(bytes == 4*1024*1024 + 11 * 1024 + 512); - - assert_se(parse_size("3B3.5G", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("3.5G3B", 1024, &bytes) == 0); - assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 3); - - assert_se(parse_size("3.5G 4B", 1024, &bytes) == 0); - assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 4); - - assert_se(parse_size("3B3G4T", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("4T3G3B", 1024, &bytes) == 0); - assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3); - - assert_se(parse_size(" 4 T 3 G 3 B", 1024, &bytes) == 0); - assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3); - - assert_se(parse_size("12P", 1024, &bytes) == 0); - assert_se(bytes == 12ULL * 1024*1024*1024*1024*1024); - - assert_se(parse_size("12P12P", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("3E 2P", 1024, &bytes) == 0); - assert_se(bytes == (3 * 1024 + 2ULL) * 1024*1024*1024*1024*1024); - - assert_se(parse_size("12X", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("12.5X", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("12.5e3", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("1024E", 1024, &bytes) == -ERANGE); - assert_se(parse_size("-1", 1024, &bytes) == -ERANGE); - assert_se(parse_size("-1024E", 1024, &bytes) == -ERANGE); - - assert_se(parse_size("-1024P", 1024, &bytes) == -ERANGE); - - assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE); -} - -static void test_config_parse_iec_off(void) { - off_t offset = 0; - assert_se(config_parse_iec_off(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0); - assert_se(offset == 4 * 1024 * 1024); - - assert_se(config_parse_iec_off(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0); -} - -static void test_strextend(void) { - _cleanup_free_ char *str = strdup("0123"); - strextend(&str, "456", "78", "9", NULL); - assert_se(streq(str, "0123456789")); -} - -static void test_strrep(void) { - _cleanup_free_ char *one, *three, *zero; - one = strrep("waldo", 1); - three = strrep("waldo", 3); - zero = strrep("waldo", 0); - - assert_se(streq(one, "waldo")); - assert_se(streq(three, "waldowaldowaldo")); - assert_se(streq(zero, "")); -} - -static void test_split_pair(void) { - _cleanup_free_ char *a = NULL, *b = NULL; - - assert_se(split_pair("", "", &a, &b) == -EINVAL); - assert_se(split_pair("foo=bar", "", &a, &b) == -EINVAL); - assert_se(split_pair("", "=", &a, &b) == -EINVAL); - assert_se(split_pair("foo=bar", "=", &a, &b) >= 0); - assert_se(streq(a, "foo")); - assert_se(streq(b, "bar")); - free(a); - free(b); - assert_se(split_pair("==", "==", &a, &b) >= 0); - assert_se(streq(a, "")); - assert_se(streq(b, "")); - free(a); - free(b); - - assert_se(split_pair("===", "==", &a, &b) >= 0); - assert_se(streq(a, "")); - assert_se(streq(b, "=")); -} - -static void test_fstab_node_to_udev_node(void) { - char *n; - - n = fstab_node_to_udev_node("LABEL=applé/jack"); - puts(n); - assert_se(streq(n, "/dev/disk/by-label/applé\\x2fjack")); - free(n); - - n = fstab_node_to_udev_node("PARTLABEL=pinkié pie"); - puts(n); - assert_se(streq(n, "/dev/disk/by-partlabel/pinkié\\x20pie")); - free(n); - - n = fstab_node_to_udev_node("UUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); - puts(n); - assert_se(streq(n, "/dev/disk/by-uuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); - free(n); - - n = fstab_node_to_udev_node("PARTUUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); - puts(n); - assert_se(streq(n, "/dev/disk/by-partuuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); - free(n); - - n = fstab_node_to_udev_node("PONIES=awesome"); - puts(n); - assert_se(streq(n, "PONIES=awesome")); - free(n); - - n = fstab_node_to_udev_node("/dev/xda1"); - puts(n); - assert_se(streq(n, "/dev/xda1")); - free(n); -} - -static void test_get_files_in_directory(void) { - _cleanup_strv_free_ char **l = NULL, **t = NULL; - - assert_se(get_files_in_directory("/tmp", &l) >= 0); - assert_se(get_files_in_directory(".", &t) >= 0); - assert_se(get_files_in_directory(".", NULL) >= 0); -} - static void test_in_set(void) { assert_se(IN_SET(1, 1)); assert_se(IN_SET(1, 1, 2, 3, 4)); @@ -1085,50 +184,6 @@ static void test_in_set(void) { assert_se(!IN_SET(0, 1, 2, 3, 4)); } -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], ""); - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - 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_hexdump(void) { - uint8_t data[146]; - unsigned i; - - hexdump(stdout, NULL, 0); - hexdump(stdout, "", 0); - hexdump(stdout, "", 1); - hexdump(stdout, "x", 1); - hexdump(stdout, "x", 2); - hexdump(stdout, "foobar", 7); - hexdump(stdout, "f\nobar", 7); - hexdump(stdout, "xxxxxxxxxxxxxxxxxxxxyz", 23); - - for (i = 0; i < ELEMENTSOF(data); i++) - data[i] = i*2; - - hexdump(stdout, data, sizeof(data)); -} - static void test_log2i(void) { assert_se(log2i(1) == 0); assert_se(log2i(2) == 1); @@ -1140,331 +195,6 @@ static void test_log2i(void) { assert_se(log2i(INT_MAX) == sizeof(int)*8-2); } -static void test_foreach_string(void) { - const char * const t[] = { - "foo", - "bar", - "waldo", - NULL - }; - const char *x; - unsigned i = 0; - - FOREACH_STRING(x, "foo", "bar", "waldo") - assert_se(streq_ptr(t[i++], x)); - - assert_se(i == 3); - - FOREACH_STRING(x, "zzz") - assert_se(streq(x, "zzz")); -} - -static void test_filename_is_valid(void) { - char foo[FILENAME_MAX+2]; - int i; - - 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_valid(foo)); - - assert_se(filename_is_valid("foo_bar-333")); - assert_se(filename_is_valid("o.o")); -} - -static void test_string_has_cc(void) { - assert_se(string_has_cc("abc\1", NULL)); - assert_se(string_has_cc("abc\x7f", NULL)); - assert_se(string_has_cc("abc\x7f", NULL)); - assert_se(string_has_cc("abc\t\x7f", "\t")); - assert_se(string_has_cc("abc\t\x7f", "\t")); - assert_se(string_has_cc("\x7f", "\t")); - assert_se(string_has_cc("\x7f", "\t\a")); - - assert_se(!string_has_cc("abc\t\t", "\t")); - assert_se(!string_has_cc("abc\t\t\a", "\t\a")); - assert_se(!string_has_cc("a\ab\tc", "\t\a")); -} - -static void test_ascii_strlower(void) { - char a[] = "AabBcC Jk Ii Od LKJJJ kkd LK"; - assert_se(streq(ascii_strlower(a), "aabbcc jk ii od lkjjj kkd lk")); -} - -static void test_files_same(void) { - _cleanup_close_ int fd = -1; - char name[] = "/tmp/test-files_same.XXXXXX"; - char name_alias[] = "/tmp/test-files_same.alias"; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(symlink(name, name_alias) >= 0); - - assert_se(files_same(name, name)); - assert_se(files_same(name, name_alias)); - - unlink(name); - unlink(name_alias); -} - -static void test_is_valid_documentation_url(void) { - 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(!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) { - char *t; - - t = file_in_same_dir("/", "a"); - assert_se(streq(t, "/a")); - free(t); - - t = file_in_same_dir("/", "/a"); - assert_se(streq(t, "/a")); - free(t); - - t = file_in_same_dir("", "a"); - assert_se(streq(t, "a")); - free(t); - - t = file_in_same_dir("a/", "a"); - assert_se(streq(t, "a/a")); - free(t); - - t = file_in_same_dir("bar/foo", "bar"); - assert_se(streq(t, "bar/bar")); - free(t); -} - -static void test_endswith(void) { - assert_se(endswith("foobar", "bar")); - assert_se(endswith("foobar", "")); - assert_se(endswith("foobar", "foobar")); - assert_se(endswith("", "")); - - assert_se(!endswith("foobar", "foo")); - assert_se(!endswith("foobar", "foobarfoofoo")); -} - -static void test_close_nointr(void) { - char name[] = "/tmp/test-test-close_nointr.XXXXXX"; - int fd; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(close_nointr(fd) >= 0); - assert_se(close_nointr(fd) < 0); - - unlink(name); -} - - -static void test_unlink_noerrno(void) { - char name[] = "/tmp/test-close_nointr.XXXXXX"; - int fd; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(close_nointr(fd) >= 0); - - { - PROTECT_ERRNO; - errno = -42; - assert_se(unlink_noerrno(name) >= 0); - assert_se(errno == -42); - assert_se(unlink_noerrno(name) < 0); - assert_se(errno == -42); - } -} - -static void test_readlink_and_make_absolute(void) { - char tempdir[] = "/tmp/test-readlink_and_make_absolute"; - char name[] = "/tmp/test-readlink_and_make_absolute/original"; - char name2[] = "test-readlink_and_make_absolute/original"; - char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias"; - char *r = NULL; - - assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid()) >= 0); - assert_se(touch(name) >= 0); - - assert_se(symlink(name, name_alias) >= 0); - assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); - assert_se(streq(r, name)); - free(r); - assert_se(unlink(name_alias) >= 0); - - assert_se(chdir(tempdir) >= 0); - assert_se(symlink(name2, name_alias) >= 0); - assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); - assert_se(streq(r, name)); - free(r); - assert_se(unlink(name_alias) >= 0); - - assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); -} - -static void test_ignore_signals(void) { - assert_se(ignore_signals(SIGINT, -1) >= 0); - assert_se(kill(getpid(), SIGINT) >= 0); - assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); - assert_se(kill(getpid(), SIGUSR1) >= 0); - assert_se(kill(getpid(), SIGUSR2) >= 0); - assert_se(kill(getpid(), SIGTERM) >= 0); - assert_se(kill(getpid(), SIGPIPE) >= 0); - assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); -} - -static void test_strshorten(void) { - char s[] = "foobar"; - - assert_se(strlen(strshorten(s, 6)) == 6); - assert_se(strlen(strshorten(s, 12)) == 6); - assert_se(strlen(strshorten(s, 2)) == 2); - assert_se(strlen(strshorten(s, 0)) == 0); -} - -static void test_strjoina(void) { - char *actual; - - actual = strjoina("", "foo", "bar"); - assert_se(streq(actual, "foobar")); - - actual = strjoina("foo", "bar", "baz"); - assert_se(streq(actual, "foobarbaz")); - - 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) { - char name[] = "/tmp/test-is_symlink.XXXXXX"; - char name_link[] = "/tmp/test-is_symlink.link"; - _cleanup_close_ int fd = -1; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(symlink(name, name_link) >= 0); - - assert_se(is_symlink(name) == 0); - assert_se(is_symlink(name_link) == 1); - assert_se(is_symlink("/a/file/which/does/not/exist/i/guess") < 0); - - - unlink(name); - unlink(name_link); -} - -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; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - 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; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - 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_glob_exists(void) { - char name[] = "/tmp/test-glob_exists.XXXXXX"; - int fd = -1; - int r; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - close(fd); - - r = glob_exists("/tmp/test-glob_exists*"); - assert_se(r == 1); - - r = unlink(name); - assert_se(r == 0); - r = glob_exists("/tmp/test-glob_exists*"); - assert_se(r == 0); -} - static void test_execute_directory(void) { char template_lo[] = "/tmp/test-readlink_and_make_absolute-lo.XXXXXXX"; char template_hi[] = "/tmp/test-readlink_and_make_absolute-hi.XXXXXXX"; @@ -1509,397 +239,6 @@ static void test_execute_directory(void) { (void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL); } -static void test_unquote_first_word(void) { - const char *p, *original; - char *t; - - p = original = "foobar waldo"; - assert_se(unquote_first_word(&p, &t, 0) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(p == original + 7); - - assert_se(unquote_first_word(&p, &t, 0) > 0); - assert_se(streq(t, "waldo")); - free(t); - assert_se(p == original + 12); - - assert_se(unquote_first_word(&p, &t, 0) == 0); - assert_se(!t); - assert_se(p == original + 12); - - p = original = "\"foobar\" \'waldo\'"; - assert_se(unquote_first_word(&p, &t, 0) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(p == original + 9); - - assert_se(unquote_first_word(&p, &t, 0) > 0); - assert_se(streq(t, "waldo")); - free(t); - assert_se(p == original + 16); - - assert_se(unquote_first_word(&p, &t, 0) == 0); - assert_se(!t); - assert_se(p == original + 16); - - p = original = "\""; - assert_se(unquote_first_word(&p, &t, 0) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\'"; - assert_se(unquote_first_word(&p, &t, 0) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\'fooo"; - assert_se(unquote_first_word(&p, &t, 0) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\'fooo"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0); - assert_se(streq(t, "fooo")); - free(t); - assert_se(p == original + 5); - - p = original = "yay\'foo\'bar"; - assert_se(unquote_first_word(&p, &t, 0) > 0); - assert_se(streq(t, "yayfoobar")); - free(t); - assert_se(p == original + 11); - - p = original = " foobar "; - assert_se(unquote_first_word(&p, &t, 0) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(p == original + 12); - - p = original = " foo\\ba\\x6ar "; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0); - assert_se(streq(t, "foo\ba\x6ar")); - free(t); - assert_se(p == original + 13); - - p = original = " foo\\ba\\x6ar "; - assert_se(unquote_first_word(&p, &t, 0) > 0); - assert_se(streq(t, "foobax6ar")); - free(t); - assert_se(p == original + 13); - - p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0); - assert_se(streq(t, "föo")); - free(t); - assert_se(p == original + 13); - - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) > 0); - assert_se(streq(t, "pi\360\237\222\251le")); - free(t); - assert_se(p == original + 32); - - p = original = "fooo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0); - assert_se(streq(t, "fooo")); - free(t); - assert_se(p == original + 5); - - p = original = "fooo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(p == original + 5); - - p = original = "fooo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(p == original + 5); - - p = original = "fooo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(unquote_first_word(&p, &t, 0) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0); - assert_se(streq(t, "foo")); - free(t); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0); - assert_se(streq(t, "foo\\")); - free(t); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0); - assert_se(streq(t, "foo\\")); - free(t); - assert_se(p == original + 5); - - p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_RELAX) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE_RELAX|UNQUOTE_RELAX) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) == -EINVAL); - assert_se(p == original + 5); - - p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "fooo\\ bar")); - free(t); - assert_se(p == original + 10); - - p = original = "\\w+@\\K[\\d.]+"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\\w+@\\K[\\d.]+"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "\\w+@\\K[\\d.]+")); - free(t); - assert_se(p == original + 12); - - p = original = "\\w+\\b"; - assert_se(unquote_first_word(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "\\w+\b")); - free(t); - assert_se(p == original + 5); -} - -static void test_unquote_first_word_and_warn(void) { - const char *p, *original; - char *t; - - p = original = "foobar waldo"; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(p == original + 7); - - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "waldo")); - free(t); - assert_se(p == original + 12); - - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == 0); - assert_se(!t); - assert_se(p == original + 12); - - p = original = "\"foobar\" \'waldo\'"; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(p == original + 9); - - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "waldo")); - free(t); - assert_se(p == original + 16); - - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == 0); - assert_se(!t); - assert_se(p == original + 16); - - p = original = "\""; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\'"; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\'fooo"; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\'fooo"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo")); - free(t); - assert_se(p == original + 5); - - p = original = " foo\\ba\\x6ar "; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foo\ba\x6ar")); - free(t); - assert_se(p == original + 13); - - p = original = " foo\\ba\\x6ar "; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foobax6ar")); - free(t); - assert_se(p == original + 13); - - p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "föo")); - free(t); - assert_se(p == original + 13); - - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "pi\360\237\222\251le")); - free(t); - assert_se(p == original + 32); - - p = original = "fooo\\"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo")); - free(t); - assert_se(p == original + 5); - - p = original = "fooo\\"; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(p == original + 5); - - p = original = "fooo\\"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foo")); - free(t); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE|UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foo")); - free(t); - assert_se(p == original + 5); - - p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word_and_warn(&p, &t, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo\\ bar")); - free(t); - assert_se(p == original + 10); - - p = original = "\\w+@\\K[\\d.]+"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "\\w+@\\K[\\d.]+")); - free(t); - assert_se(p == original + 12); - - p = original = "\\w+\\b"; - assert_se(unquote_first_word_and_warn(&p, &t, UNQUOTE_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "\\w+\b")); - free(t); - assert_se(p == original + 5); -} - -static void test_unquote_many_words(void) { - const char *p, *original; - char *a, *b, *c; - - p = original = "foobar waldi piep"; - assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 3); - assert_se(p == original + 17); - assert_se(streq_ptr(a, "foobar")); - assert_se(streq_ptr(b, "waldi")); - assert_se(streq_ptr(c, "piep")); - free(a); - free(b); - free(c); - - p = original = "'foobar' wa\"ld\"i "; - assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 2); - assert_se(p == original + 19); - assert_se(streq_ptr(a, "foobar")); - assert_se(streq_ptr(b, "waldi")); - assert_se(streq_ptr(c, NULL)); - free(a); - free(b); - - p = original = ""; - assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 0); - assert_se(p == original); - assert_se(streq_ptr(a, NULL)); - assert_se(streq_ptr(b, NULL)); - assert_se(streq_ptr(c, NULL)); - - p = original = " "; - assert_se(unquote_many_words(&p, 0, &a, &b, &c, NULL) == 0); - assert_se(p == original+2); - assert_se(streq_ptr(a, NULL)); - assert_se(streq_ptr(b, NULL)); - assert_se(streq_ptr(c, NULL)); - - p = original = "foobar"; - assert_se(unquote_many_words(&p, 0, NULL) == 0); - assert_se(p == original); - - p = original = "foobar waldi"; - assert_se(unquote_many_words(&p, 0, &a, NULL) == 1); - assert_se(p == original+7); - assert_se(streq_ptr(a, "foobar")); - free(a); - - p = original = " foobar "; - assert_se(unquote_many_words(&p, 0, &a, NULL) == 1); - assert_se(p == original+15); - assert_se(streq_ptr(a, "foobar")); - free(a); -} - -static int parse_item(const char *key, const char *value) { - assert_se(key); - - log_info("kernel cmdline option <%s> = <%s>", key, strna(value)); - return 0; -} - -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; @@ -1907,7 +246,7 @@ static void test_raw_clone(void) { log_info("before clone: getpid()→"PID_FMT, parent); assert_se(raw_getpid() == parent); - pid = raw_clone(0, NULL); + pid = raw_clone(0); assert_se(pid >= 0); pid2 = raw_getpid(); @@ -1925,239 +264,107 @@ static void test_raw_clone(void) { } } -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_physical_memory(void) { + uint64_t p; + char buf[FORMAT_BYTES_MAX]; + + p = physical_memory(); + assert_se(p > 0); + assert_se(p < UINT64_MAX); + assert_se(p % page_size() == 0); + + log_info("Memory: %s (%" PRIu64 ")", format_bytes(buf, sizeof(buf), p), p); } -static void test_uid_ptr(void) { +static void test_physical_memory_scale(void) { + uint64_t p; - assert_se(UID_TO_PTR(0) != NULL); - assert_se(UID_TO_PTR(1000) != NULL); + p = physical_memory(); - assert_se(PTR_TO_UID(UID_TO_PTR(0)) == 0); - assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000); -} + assert_se(physical_memory_scale(0, 100) == 0); + assert_se(physical_memory_scale(100, 100) == p); -static void test_sparse_write_one(int fd, const char *buffer, size_t n) { - char check[n]; + log_info("Memory original: %" PRIu64, physical_memory()); + log_info("Memory scaled by 50%%: %" PRIu64, physical_memory_scale(50, 100)); + log_info("Memory divided by 2: %" PRIu64, physical_memory() / 2); + log_info("Page size: %zu", page_size()); - 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); + /* There might be an uneven number of pages, hence permit these calculations to be half a page off... */ + assert_se(page_size()/2 + physical_memory_scale(50, 100) - p/2 <= page_size()); + assert_se(physical_memory_scale(200, 100) == p*2); - assert_se(lseek(fd, 0, SEEK_CUR) == (off_t) n); - assert_se(ftruncate(fd, n) >= 0); + assert_se(physical_memory_scale(0, 1) == 0); + assert_se(physical_memory_scale(1, 1) == p); + assert_se(physical_memory_scale(2, 1) == p*2); - assert_se(lseek(fd, 0, SEEK_SET) == 0); - assert_se(read(fd, check, n) == (ssize_t) n); + assert_se(physical_memory_scale(0, 2) == 0); - assert_se(memcmp(buffer, check, n) == 0); -} + assert_se(page_size()/2 + physical_memory_scale(1, 2) - p/2 <= page_size()); + assert_se(physical_memory_scale(2, 2) == p); + assert_se(physical_memory_scale(4, 2) == p*2); -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)); + assert_se(physical_memory_scale(0, UINT32_MAX) == 0); + assert_se(physical_memory_scale(UINT32_MAX, UINT32_MAX) == p); + + /* overflow */ + assert_se(physical_memory_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX); } -static void test_shell_maybe_quote_one(const char *s, const char *expected) { - _cleanup_free_ char *r; +static void test_system_tasks_max(void) { + uint64_t t; + + t = system_tasks_max(); + assert_se(t > 0); + assert_se(t < UINT64_MAX); - assert_se(r = shell_maybe_quote(s)); - assert_se(streq(r, expected)); + log_info("Max tasks: %" PRIu64, t); } -static void test_shell_maybe_quote(void) { +static void test_system_tasks_max_scale(void) { + uint64_t t; - test_shell_maybe_quote_one("", ""); - test_shell_maybe_quote_one("\\", "\"\\\\\""); - test_shell_maybe_quote_one("\"", "\"\\\"\""); - test_shell_maybe_quote_one("foobar", "foobar"); - test_shell_maybe_quote_one("foo bar", "\"foo bar\""); - test_shell_maybe_quote_one("foo \"bar\" waldo", "\"foo \\\"bar\\\" waldo\""); - test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\""); -} + t = system_tasks_max(); -static void test_parse_mode(void) { - mode_t m; + assert_se(system_tasks_max_scale(0, 100) == 0); + assert_se(system_tasks_max_scale(100, 100) == t); - assert_se(parse_mode("-1", &m) < 0); - assert_se(parse_mode("", &m) < 0); - assert_se(parse_mode("888", &m) < 0); - assert_se(parse_mode("77777", &m) < 0); + assert_se(system_tasks_max_scale(0, 1) == 0); + assert_se(system_tasks_max_scale(1, 1) == t); + assert_se(system_tasks_max_scale(2, 1) == 2*t); - assert_se(parse_mode("544", &m) >= 0 && m == 0544); - assert_se(parse_mode("777", &m) >= 0 && m == 0777); - assert_se(parse_mode("7777", &m) >= 0 && m == 07777); - assert_se(parse_mode("0", &m) >= 0 && m == 0); -} + assert_se(system_tasks_max_scale(0, 2) == 0); + assert_se(system_tasks_max_scale(1, 2) == t/2); + assert_se(system_tasks_max_scale(2, 2) == t); + assert_se(system_tasks_max_scale(3, 2) == (3*t)/2); + assert_se(system_tasks_max_scale(4, 2) == t*2); + + assert_se(system_tasks_max_scale(0, UINT32_MAX) == 0); + assert_se(system_tasks_max_scale((UINT32_MAX-1)/2, UINT32_MAX-1) == t/2); + assert_se(system_tasks_max_scale(UINT32_MAX, UINT32_MAX) == t); + + /* overflow */ -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); + assert_se(system_tasks_max_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX); } int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - test_streq_ptr(); test_align_power2(); test_max(); test_container_of(); - test_alloca(); test_div_round_up(); - test_first_word(); - test_close_many(); - test_parse_boolean(); - test_parse_pid(); - test_parse_uid(); - test_safe_atolli(); - test_safe_atod(); - test_strappend(); - test_strstrip(); - test_delete_chars(); - test_in_charset(); - test_hexchar(); - test_unhexchar(); - test_base32hexchar(); - test_unbase32hexchar(); - test_base64char(); - test_unbase64char(); - test_octchar(); - test_unoctchar(); - test_decchar(); - test_undecchar(); - test_unhexmem(); - test_base32hexmem(); - test_unbase32hexmem(); - test_base64mem(); - test_unbase64mem(); - test_cescape(); - test_cunescape(); - test_foreach_word(); - test_foreach_word_quoted(); - test_memdup_multiply(); - test_hostname_is_valid(); - test_read_hostname_config(); test_u64log2(); test_protect_errno(); - test_parse_size(); - test_config_parse_iec_off(); - test_strextend(); - test_strrep(); - test_split_pair(); - test_fstab_node_to_udev_node(); - test_get_files_in_directory(); test_in_set(); - test_writing_tmpfile(); - test_hexdump(); test_log2i(); - test_foreach_string(); - test_filename_is_valid(); - test_string_has_cc(); - test_ascii_strlower(); - test_files_same(); - test_is_valid_documentation_url(); - test_file_in_same_dir(); - test_endswith(); - test_close_nointr(); - test_unlink_noerrno(); - test_readlink_and_make_absolute(); - test_ignore_signals(); - test_strshorten(); - test_strjoina(); - test_is_symlink(); - test_search_and_fopen(); - test_search_and_fopen_nulstr(); - test_glob_exists(); test_execute_directory(); - test_unquote_first_word(); - test_unquote_first_word_and_warn(); - test_unquote_many_words(); - test_parse_proc_cmdline(); test_raw_clone(); - test_same_fd(); - test_uid_ptr(); - test_sparse_write(); - test_shell_maybe_quote(); - test_parse_mode(); - test_tempfn(); + test_physical_memory(); + test_physical_memory_scale(); + test_system_tasks_max(); + test_system_tasks_max_scale(); return 0; } diff --git a/src/test/test-watchdog.c b/src/test/test-watchdog.c index 2e5d0c3aae..e3c19647fc 100644 --- a/src/test/test-watchdog.c +++ b/src/test/test-watchdog.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,8 +19,8 @@ #include <unistd.h> -#include "watchdog.h" #include "log.h" +#include "watchdog.h" int main(int argc, char *argv[]) { usec_t t = 10 * USEC_PER_SEC; diff --git a/src/test/test-web-util.c b/src/test/test-web-util.c new file mode 100644 index 0000000000..79a3a13af6 --- /dev/null +++ b/src/test/test-web-util.c @@ -0,0 +1,39 @@ +/*** + This file is part of systemd. + + Copyright 2010 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 "macro.h" +#include "web-util.h" + +static void test_is_valid_documentation_url(void) { + 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(!documentation_url_is_valid("foo:")); + assert_se(!documentation_url_is_valid("info:")); + assert_se(!documentation_url_is_valid("")); +} + +int main(int argc, char *argv[]) { + test_is_valid_documentation_url(); + + return 0; +} diff --git a/src/test/test-xattr-util.c b/src/test/test-xattr-util.c new file mode 100644 index 0000000000..267f29426c --- /dev/null +++ b/src/test/test-xattr-util.c @@ -0,0 +1,69 @@ +/*** + This file is part of systemd. + + Copyright 2010 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 <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/xattr.h> +#include <unistd.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "fs-util.h" +#include "macro.h" +#include "string-util.h" +#include "xattr-util.h" + +static void test_fgetxattrat_fake(void) { + char t[] = "/var/tmp/xattrtestXXXXXX"; + _cleanup_close_ int fd = -1; + const char *x; + char v[3] = {}; + int r; + + assert_se(mkdtemp(t)); + x = strjoina(t, "/test"); + assert_se(touch(x) >= 0); + + r = setxattr(x, "user.foo", "bar", 3, 0); + if (r < 0 && errno == EOPNOTSUPP) /* no xattrs supported on /var/tmp... */ + goto cleanup; + assert_se(r >= 0); + + fd = open(t, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); + assert_se(fd >= 0); + + assert_se(fgetxattrat_fake(fd, "test", "user.foo", v, 3, 0) >= 0); + assert_se(memcmp(v, "bar", 3) == 0); + + safe_close(fd); + fd = open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); + assert_se(fd >= 0); + assert_se(fgetxattrat_fake(fd, "usr", "user.idontexist", v, 3, 0) == -ENODATA); + +cleanup: + assert_se(unlink(x) >= 0); + assert_se(rmdir(t) >= 0); +} + +int main(void) { + test_fgetxattrat_fake(); + + return 0; +} diff --git a/src/test/test-xml.c b/src/test/test-xml.c index ea109fbde0..b0b72fa78a 100644 --- a/src/test/test-xml.c +++ b/src/test/test-xml.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,8 +19,10 @@ #include <stdarg.h> -#include "xml.h" +#include "alloc-util.h" +#include "string-util.h" #include "util.h" +#include "xml.h" static void test_one(const char *data, ...) { void *state = NULL; |