/* * ProFTPD - FTP server testsuite * Copyright (c) 2015-2020 The ProFTPD Project team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * * As a special exemption, The ProFTPD Project team and other respective * copyright holders give permission to link this program with OpenSSL, and * distribute the resulting executable, without including the source code for * OpenSSL in the source distribution. */ /* Miscellaneous tests */ #include "tests.h" static pool *p = NULL; static unsigned int schedule_called = 0; static const char *misc_test_shutmsg = "/tmp/prt-shutmsg.dat"; static const char *misc_test_readlink = "/tmp/prt-readlink.lnk"; static const char *misc_test_readlink2_dir = "/tmp/prt-readlink/"; static const char *misc_test_readlink2 = "/tmp/prt-readlink/test.lnk"; /* Fixtures */ static void set_up(void) { (void) unlink(misc_test_readlink); (void) unlink(misc_test_readlink2); (void) unlink(misc_test_shutmsg); (void) rmdir(misc_test_readlink2_dir); if (p == NULL) { p = permanent_pool = make_sub_pool(NULL); } init_fs(); pr_fs_statcache_set_policy(PR_TUNABLE_FS_STATCACHE_SIZE, PR_TUNABLE_FS_STATCACHE_MAX_AGE, 0); if (getenv("TEST_VERBOSE") != NULL) { pr_trace_set_levels("auth", 1, 20); pr_trace_set_levels("fsio", 1, 20); pr_trace_set_levels("fs.statcache", 1, 20); } schedule_called = 0; session.user = NULL; } static void tear_down(void) { (void) unlink(misc_test_readlink); (void) unlink(misc_test_readlink2); (void) unlink(misc_test_shutmsg); (void) rmdir(misc_test_readlink2_dir); pr_fs_statcache_set_policy(PR_TUNABLE_FS_STATCACHE_SIZE, PR_TUNABLE_FS_STATCACHE_MAX_AGE, 0); if (getenv("TEST_VERBOSE") != NULL) { pr_trace_set_levels("auth", 0, 0); pr_trace_set_levels("fsio", 0, 0); pr_trace_set_levels("fs.statcache", 0, 0); } session.user = NULL; if (p) { destroy_pool(p); p = session.pool = permanent_pool = NULL; } } static void schedule_cb(void *arg1, void *arg2, void *arg3, void *arg4) { schedule_called++; } /* Tests */ START_TEST (schedule_test) { mark_point(); schedule(NULL, 0, NULL, NULL, NULL, NULL); mark_point(); schedule(schedule_cb, -1, NULL, NULL, NULL, NULL); mark_point(); run_schedule(); mark_point(); schedule(schedule_cb, 0, NULL, NULL, NULL, NULL); run_schedule(); fail_unless(schedule_called == 1, "Expected 1, got %u", schedule_called); run_schedule(); fail_unless(schedule_called == 1, "Expected 1, got %u", schedule_called); mark_point(); schedule(schedule_cb, 0, NULL, NULL, NULL, NULL); schedule(schedule_cb, 0, NULL, NULL, NULL, NULL); run_schedule(); fail_unless(schedule_called == 3, "Expected 3, got %u", schedule_called); run_schedule(); fail_unless(schedule_called == 3, "Expected 3, got %u", schedule_called); mark_point(); /* Schedule this callback to run after 2 "loops", i.e. calls to * run_schedule(). */ schedule(schedule_cb, 2, NULL, NULL, NULL, NULL); run_schedule(); fail_unless(schedule_called == 3, "Expected 3, got %u", schedule_called); run_schedule(); fail_unless(schedule_called == 3, "Expected 3, got %u", schedule_called); run_schedule(); fail_unless(schedule_called == 4, "Expected 4, got %u", schedule_called); } END_TEST START_TEST (get_name_max_test) { long res; char *path; int fd; res = get_name_max(NULL, -1); fail_unless(res < 0, "Failed to handle invalid arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); path = "/"; res = get_name_max(path, -1); fail_if(res < 0, "Failed to handle path '%s': %s", path, strerror(errno)); fd = 1; res = get_name_max(NULL, fd); /* It seems that fpathconf(2) on some platforms will handle stdin as a * valid file descriptor, and some will not. */ if (res < 0) { fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); } } END_TEST START_TEST (dir_interpolate_test) { char *res; const char *path; res = dir_interpolate(NULL, NULL); fail_unless(res == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = dir_interpolate(p, NULL); fail_unless(res == NULL, "Failed to handle null path"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); mark_point(); path = "/foo"; res = dir_interpolate(p, path); fail_unless(path != NULL, "Failed to interpolate '%s': %s", path, strerror(errno)); fail_unless(strcmp(res, path) == 0, "Expected '%s', got '%s'", path, res); mark_point(); path = "~foo.bar.bar.quxx.quzz/foo"; res = dir_interpolate(p, path); fail_unless(path != NULL, "Failed to interpolate '%s': %s", path, strerror(errno)); fail_unless(*path == '~', "Interpolated path with unknown user unexpectedly"); fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT, strerror(errno), errno); } END_TEST START_TEST (dir_best_path_test) { char *res; const char *path; res = dir_best_path(NULL, NULL); fail_unless(res == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = dir_best_path(p, NULL); fail_unless(res == NULL, "Failed to handle null path"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); mark_point(); path = "/foo"; res = dir_best_path(p, path); fail_unless(path != NULL, "Failed to get best path for '%s': %s", path, strerror(errno)); fail_unless(strcmp(res, path) == 0, "Expected '%s', got '%s'", path, res); } END_TEST START_TEST (dir_canonical_path_test) { char *res; const char *path; res = dir_canonical_path(NULL, NULL); fail_unless(res == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = dir_canonical_path(p, NULL); fail_unless(res == NULL, "Failed to handle null path"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); mark_point(); path = "/foo"; res = dir_canonical_path(p, path); fail_unless(path != NULL, "Failed to get canonical path for '%s': %s", path, strerror(errno)); fail_unless(strcmp(res, path) == 0, "Expected '%s', got '%s'", path, res); } END_TEST START_TEST (dir_canonical_vpath_test) { char *res; const char *path; res = dir_canonical_vpath(NULL, NULL); fail_unless(res == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = dir_canonical_vpath(p, NULL); fail_unless(res == NULL, "Failed to handle null path"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); mark_point(); path = "/foo"; res = dir_canonical_vpath(p, path); fail_unless(path != NULL, "Failed to get canonical vpath for '%s': %s", path, strerror(errno)); fail_unless(strcmp(res, path) == 0, "Expected '%s', got '%s'", path, res); } END_TEST START_TEST (dir_readlink_test) { int res, flags = 0; const char *path; char *buf, *dst_path, *expected_path; size_t bufsz, dst_pathlen, expected_pathlen; (void) unlink(misc_test_readlink); /* Parameter validation */ res = dir_readlink(NULL, NULL, NULL, 0, flags); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = dir_readlink(p, NULL, NULL, 0, flags); fail_unless(res < 0, "Failed to handle null path"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); path = misc_test_readlink; res = dir_readlink(p, path, NULL, 0, flags); fail_unless(res < 0, "Failed to handle null buffer"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); bufsz = 1024; buf = palloc(p, bufsz); res = dir_readlink(p, path, buf, 0, flags); fail_unless(res == 0, "Failed to handle zero buffer length"); res = dir_readlink(p, path, buf, bufsz, flags); fail_unless(res < 0, "Failed to handle nonexistent file"); fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT, strerror(errno), errno); dst_path = ""; res = symlink(dst_path, path); if (res == 0) { /* Some platforms will not allow creation of empty symlinks. Nice of * them. */ res = dir_readlink(p, path, buf, bufsz, flags); fail_unless(res == 0, "Failed to handle empty symlink"); } (void) unlink(path); /* Not chrooted, absolute dst path */ memset(buf, '\0', bufsz); dst_path = "/home/user/file.dat"; dst_pathlen = strlen(dst_path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == dst_pathlen, "Expected length %lu, got %d", (unsigned long) dst_pathlen, res); fail_unless(strcmp(buf, dst_path) == 0, "Expected '%s', got '%s'", dst_path, buf); /* Not chrooted, relative dst path, flags to ignore rel path */ memset(buf, '\0', bufsz); dst_path = "./file.dat"; dst_pathlen = strlen(dst_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == dst_pathlen, "Expected length %lu, got %d", (unsigned long) dst_pathlen, res); fail_unless(strcmp(buf, dst_path) == 0, "Expected '%s', got '%s'", dst_path, buf); /* Not chrooted, relative dst path without leading '.', flags to ignore rel * path. */ memset(buf, '\0', bufsz); dst_path = "file.dat"; dst_pathlen = strlen(dst_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == dst_pathlen, "Expected length %lu, got %d", (unsigned long) dst_pathlen, res); fail_unless(strcmp(buf, dst_path) == 0, "Expected '%s', got '%s'", dst_path, buf); /* Not chrooted, relative dst path, flags to HANDLE rel path */ memset(buf, '\0', bufsz); dst_path = "./file.dat"; dst_pathlen = strlen(dst_path); expected_path = "/tmp/file.dat"; expected_pathlen = strlen(expected_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH; res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d", (unsigned long) expected_pathlen, res); fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'", expected_path, buf); /* Not chrooted, relative dst path without leading '.', flags to HANDLE rel * path. */ memset(buf, '\0', bufsz); dst_path = "file.dat"; dst_pathlen = strlen(dst_path); expected_path = "/tmp/file.dat"; expected_pathlen = strlen(expected_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH; res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d", (unsigned long) expected_pathlen, res); fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'", expected_path, buf); /* Not chrooted, dst path longer than given buffer */ flags = 0; memset(buf, '\0', bufsz); res = dir_readlink(p, path, buf, 2, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless(res == 2, "Expected length 2, got %d", res); fail_unless(strncmp(buf, dst_path, 2) == 0, "Expected '%*s', got '%*s'", 2, dst_path, 2, buf); /* Chrooted to "/" */ session.chroot_path = "/"; memset(buf, '\0', bufsz); res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == dst_pathlen, "Expected length %lu, got %d", (unsigned long) dst_pathlen, res); fail_unless(strcmp(buf, dst_path) == 0, "Expected '%s', got '%s'", dst_path, buf); /* Chrooted, absolute destination path shorter than chroot path */ session.chroot_path = "/home/user"; memset(buf, '\0', bufsz); dst_path = "/foo"; dst_pathlen = strlen(dst_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == dst_pathlen, "Expected length %lu, got %d", (unsigned long) dst_pathlen, res); fail_unless(strcmp(buf, dst_path) == 0, "Expected '%s', got '%s'", dst_path, buf); /* Chrooted, overlapping chroot to non-dir */ memset(buf, '\0', bufsz); dst_path = "/home/user2"; dst_pathlen = strlen(dst_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == dst_pathlen, "Expected length %lu, got %d", (unsigned long) dst_pathlen, res); fail_unless(strcmp(buf, dst_path) == 0, "Expected '%s', got '%s'", dst_path, buf); /* Chrooted, absolute destination within chroot */ memset(buf, '\0', bufsz); dst_path = "/home/user/file.txt"; dst_pathlen = strlen(dst_path); expected_path = "/file.txt"; expected_pathlen = strlen(expected_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d", (unsigned long) expected_pathlen, res); fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'", expected_path, buf); /* Chrooted, absolute destination outside of chroot */ memset(buf, '\0', bufsz); dst_path = "/home/user/../file.txt"; dst_pathlen = strlen(dst_path); expected_path = "/home/file.txt"; expected_pathlen = strlen(expected_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d", (unsigned long) expected_pathlen, res); fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'", expected_path, buf); /* Chrooted, relative destination within chroot */ memset(buf, '\0', bufsz); dst_path = "./file.txt"; dst_pathlen = strlen(dst_path); expected_path = "./file.txt"; expected_pathlen = strlen(expected_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d", (unsigned long) expected_pathlen, res); fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'", expected_path, buf); /* Chrooted, relative destination (without leading '.') within chroot */ memset(buf, '\0', bufsz); dst_path = "file.txt"; dst_pathlen = strlen(dst_path); expected_path = "file.txt"; expected_pathlen = strlen(expected_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d", (unsigned long) expected_pathlen, res); fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'", expected_path, buf); /* Chrooted, relative destination outside of chroot */ memset(buf, '\0', bufsz); dst_path = "../file.txt"; dst_pathlen = strlen(dst_path); expected_path = "../file.txt"; expected_pathlen = strlen(expected_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); /* First, tell dir_readlink() to ignore relative destination paths. */ flags = 0; res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d", (unsigned long) expected_pathlen, res); fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'", expected_path, buf); /* Now do it again, telling dir_readlink() to handle relative destination * paths. */ memset(buf, '\0', bufsz); dst_path = "../file.txt"; dst_pathlen = strlen(dst_path); expected_path = "/file.txt"; expected_pathlen = strlen(expected_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH; res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d", (unsigned long) expected_pathlen, res); fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'", expected_path, buf); /* One more time, this time changing the chroot path to align with the * source path. */ memset(buf, '\0', bufsz); dst_path = "../file.txt"; dst_pathlen = strlen(dst_path); expected_path = "/file.txt"; expected_pathlen = strlen(expected_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); session.chroot_path = "/tmp"; flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH; res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d", (unsigned long) expected_pathlen, res); fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'", expected_path, buf); /* Now use a relative path that does not start with '.' */ memset(buf, '\0', bufsz); dst_path = "file.txt"; dst_pathlen = strlen(dst_path); expected_path = "./file.txt"; expected_pathlen = strlen(expected_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); session.chroot_path = "/tmp"; flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH; res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d (%s)", (unsigned long) expected_pathlen, res, buf); fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'", expected_path, buf); /* Now use a relative path that does not start with '.', and a chroot * deeper down than one directory. */ memset(buf, '\0', bufsz); dst_path = "file.txt"; dst_pathlen = strlen(dst_path); expected_path = "/tmp/file.txt"; expected_pathlen = strlen(expected_path); (void) unlink(path); res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); session.chroot_path = "/tmp/foo/bar"; flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH; res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d (%s)", (unsigned long) expected_pathlen, res, buf); fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'", expected_path, buf); /* Now use a relative path, and a chroot deeper down than one directory, and * a deeper/longer source path. */ memset(buf, '\0', bufsz); dst_path = "./file.txt"; dst_pathlen = strlen(dst_path); expected_path = "/tmp/prt-readlink/file.txt"; expected_pathlen = strlen(expected_path); (void) unlink(path); (void) rmdir(misc_test_readlink2_dir); (void) mkdir(misc_test_readlink2_dir, 0777); path = misc_test_readlink2; res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); session.chroot_path = "/tmp/foo/bar"; flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH; res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d (%s)", (unsigned long) expected_pathlen, res, buf); fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'", expected_path, buf); /* Now use a relative path that does not start with '.', and a chroot * deeper down than one directory, and a deeper/longer source path. */ memset(buf, '\0', bufsz); dst_path = "file.txt"; dst_pathlen = strlen(dst_path); expected_path = "/tmp/prt-readlink/file.txt"; expected_pathlen = strlen(expected_path); (void) unlink(path); (void) rmdir(misc_test_readlink2_dir); (void) mkdir(misc_test_readlink2_dir, 0777); path = misc_test_readlink2; res = symlink(dst_path, path); fail_unless(res == 0, "Failed to symlink '%s' to '%s': %s", path, dst_path, strerror(errno)); session.chroot_path = "/tmp/foo/bar"; flags = PR_DIR_READLINK_FL_HANDLE_REL_PATH; res = dir_readlink(p, path, buf, bufsz, flags); fail_if(res < 0, "Failed to read '%s' symlink: %s", path, strerror(errno)); fail_unless((size_t) res == expected_pathlen, "Expected length %lu, got %d (%s)", (unsigned long) expected_pathlen, res, buf); fail_unless(strcmp(buf, expected_path) == 0, "Expected '%s', got '%s'", expected_path, buf); (void) unlink(misc_test_readlink); (void) unlink(misc_test_readlink2); (void) rmdir(misc_test_readlink2_dir); } END_TEST START_TEST (dir_realpath_test) { char *res; const char *path; res = dir_realpath(NULL, NULL); fail_unless(res == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = dir_realpath(p, NULL); fail_unless(res == NULL, "Failed to handle null path"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); mark_point(); path = "/foo"; res = dir_realpath(p, path); fail_unless(res == NULL, "Got real path for '%s' unexpectedly", path); fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT, strerror(errno), errno); mark_point(); path = "/"; res = dir_realpath(p, path); fail_unless(res != NULL, "Failed to get real path for '%s': %s", path, strerror(errno)); fail_unless(strcmp(res, path) == 0, "Expected '%s', got '%s'", path, res); } END_TEST START_TEST (dir_abs_path_test) { char *res; const char *path; res = dir_abs_path(NULL, NULL, TRUE); fail_unless(res == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = dir_abs_path(p, NULL, TRUE); fail_unless(res == NULL, "Failed to handle null path"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); mark_point(); path = "/foo"; res = dir_abs_path(p, path, TRUE); fail_unless(path != NULL, "Failed to get absolute path for '%s': %s", path, strerror(errno)); fail_unless(strcmp(res, path) == 0, "Expected '%s', got '%s'", path, res); } END_TEST START_TEST (safe_token_test) { char *res, *text, *expected; mark_point(); expected = ""; res = safe_token(NULL); fail_unless(res != NULL, "Failed to handle null arguments"); fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected, res); mark_point(); text = ""; expected = ""; res = safe_token(&text); fail_unless(res != NULL, "Failed to handle null arguments"); fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected, res); mark_point(); text = "foo"; expected = text; res = safe_token(&text); fail_unless(res != NULL, "Failed to handle null arguments"); fail_unless(res == expected, "Expected '%s', got '%s'", expected, res); fail_unless(strcmp(text, "") == 0, "Expected '', got '%s'", text); mark_point(); text = " foo"; expected = text + 2; res = safe_token(&text); fail_unless(res != NULL, "Failed to handle null arguments"); fail_unless(res == expected, "Expected '%s', got '%s'", expected, res); fail_unless(strcmp(text, "") == 0, "Expected '', got '%s'", text); mark_point(); text = " \t"; expected = ""; res = safe_token(&text); fail_unless(res != NULL, "Failed to handle null arguments"); fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected, res); } END_TEST static int write_shutmsg(const char *path, const char *line) { FILE *fh; int res; size_t line_len; fh = fopen(path, "w+"); if (fh == NULL) { return -1; } line_len = strlen(line); fwrite(line, line_len, 1, fh); res = fclose(fh); return res; } START_TEST (check_shutmsg_test) { int res; const char *path; time_t when_shutdown = 0, when_deny = 0, when_disconnect = 0; char shutdown_msg[PR_TUNABLE_BUFFER_SIZE]; res = check_shutmsg(NULL, NULL, NULL, NULL, NULL, NULL, 0); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); path = "/foo/bar/baz/quxx/quzz"; res = check_shutmsg(p, path, NULL, NULL, NULL, NULL, 0); fail_unless(res < 0, "Failed to handle nonexistent path"); fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT, strerror(errno), errno); path = "/"; res = check_shutmsg(p, path, NULL, NULL, NULL, NULL, 0); fail_unless(res < 0, "Failed to handle directory path"); fail_unless(errno == EISDIR, "Expected EISDIR (%d), got %s (%d)", EISDIR, strerror(errno), errno); /* XXX More testing needed */ path = misc_test_shutmsg; (void) unlink(path); res = write_shutmsg(path, "1970 1 1 0 0 0 0000 0000\nGoodbye, cruel world!\n"); fail_unless(res == 0, "Failed to write '%s': %s", path, strerror(errno)); memset(shutdown_msg, '\0', sizeof(shutdown_msg)); pr_env_set(p, "TZ", "GMT"); mark_point(); res = check_shutmsg(p, path, &when_shutdown, &when_deny, &when_disconnect, shutdown_msg, sizeof(shutdown_msg)); fail_unless(res == 1, "Expected 1, got %d", res); fail_unless(when_shutdown == (time_t) 0, "Expected 0, got %lu", (unsigned long) when_shutdown); fail_unless(when_deny == (time_t) 0, "Expected 0, got %lu", (unsigned long) when_deny); fail_unless(when_disconnect == (time_t) 0, "Expected 0, got %lu", (unsigned long) when_disconnect); fail_unless(strcmp(shutdown_msg, "Goodbye, cruel world!") == 0, "Expected 'Goodbye, cruel world!', got '%s'", shutdown_msg); (void) unlink(path); res = write_shutmsg(path, "2037 1 1 0 0 0 0000 0000\nGoodbye, cruel world!\n"); fail_unless(res == 0, "Failed to write '%s': %s", path, strerror(errno)); mark_point(); res = check_shutmsg(p, path, NULL, NULL, NULL, NULL, 0); fail_unless(res == 1, "Expected 1, got %d", res); (void) unlink(path); res = write_shutmsg(path, "0 0 0 0 0 0 0000 0000\nGoodbye, cruel world!\n"); fail_unless(res == 0, "Failed to write '%s': %s", path, strerror(errno)); mark_point(); res = check_shutmsg(p, path, NULL, NULL, NULL, NULL, 0); (void) unlink(misc_test_shutmsg); } END_TEST START_TEST (memscrub_test) { size_t len; char *expected, *text; mark_point(); pr_memscrub(NULL, 1); expected = "Hello, World!"; text = pstrdup(p, expected); mark_point(); pr_memscrub(text, 0); len = strlen(text); mark_point(); pr_memscrub(text, len); fail_unless(strncmp(text, expected, len + 1) != 0, "Expected other than '%s'", expected); } END_TEST START_TEST (getopt_reset_test) { mark_point(); pr_getopt_reset(); } END_TEST START_TEST (exists_test) { int res; const char *path; res = exists(NULL); fail_unless(res == FALSE, "Failed to handle null path"); path = "/"; res = exists(path); fail_unless(res == TRUE, "Expected TRUE for path '%s', got FALSE", path); } END_TEST START_TEST (exists2_test) { int res; const char *path; res = exists2(NULL, NULL); fail_unless(res == FALSE, "Failed to handle null arguments"); res = exists2(p, NULL); fail_unless(res == FALSE, "Failed to handle null path"); path = "/"; res = exists2(p, path); fail_unless(res == TRUE, "Expected TRUE for path '%s', got FALSE", path); } END_TEST START_TEST (dir_exists_test) { int res; const char *path; res = dir_exists(NULL); fail_unless(res == FALSE, "Failed to handle null path"); path = "/"; res = dir_exists(path); fail_unless(res == TRUE, "Expected TRUE for path '%s', got FALSE", path); path = "./api-tests"; res = dir_exists(path); fail_unless(res == FALSE, "Expected FALSE for path '%s', got TRUE", path); } END_TEST START_TEST (dir_exists2_test) { int res; const char *path; res = dir_exists2(NULL, NULL); fail_unless(res == FALSE, "Failed to handle null arguments"); res = dir_exists2(p, NULL); fail_unless(res == FALSE, "Failed to handle null path"); path = "/"; res = dir_exists2(p, path); fail_unless(res == TRUE, "Expected TRUE for path '%s', got FALSE", path); path = "./api-tests"; res = dir_exists2(p, path); fail_unless(res == FALSE, "Expected FALSE for path '%s', got TRUE", path); } END_TEST START_TEST (symlink_mode_test) { mode_t res; const char *path; res = symlink_mode(NULL); fail_unless(res == 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); path = "/"; res = symlink_mode(path); fail_unless(res == 0, "Found mode for non-symlink '%s'", path); } END_TEST START_TEST (symlink_mode2_test) { mode_t res; const char *path; res = symlink_mode2(NULL, NULL); fail_unless(res == 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = symlink_mode2(p, NULL); fail_unless(res == 0, "Failed to handle null path"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); path = "/"; res = symlink_mode2(p, path); fail_unless(res == 0, "Found mode for non-symlink '%s'", path); } END_TEST START_TEST (file_mode_test) { mode_t res; const char *path; res = file_mode(NULL); fail_unless(res == 0, "Failed to handle null path"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); path = "/"; res = file_mode(path); fail_unless(res != 0, "Failed to find mode for '%s': %s", path, strerror(errno)); } END_TEST START_TEST (file_mode2_test) { mode_t res; const char *path; res = file_mode2(NULL, NULL); fail_unless(res == 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = file_mode2(p, NULL); fail_unless(res == 0, "Failed to handle null path"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); path = "/"; res = file_mode2(p, path); fail_unless(res != 0, "Failed to find mode for '%s': %s", path, strerror(errno)); } END_TEST START_TEST (file_exists_test) { int res; const char *path; res = file_exists(NULL); fail_unless(res == FALSE, "Failed to handle null path"); path = "/"; res = file_exists(path); fail_unless(res == FALSE, "Expected FALSE for path '%s', got TRUE", path); path = "./api-tests"; res = file_exists(path); fail_unless(res == TRUE, "Expected TRUE for path '%s', got FALSE", path); } END_TEST START_TEST (file_exists2_test) { int res; const char *path; res = file_exists2(NULL, NULL); fail_unless(res == FALSE, "Failed to handle null arguments"); res = file_exists2(p, NULL); fail_unless(res == FALSE, "Failed to handle null path"); path = "/"; res = file_exists2(p, path); fail_unless(res == FALSE, "Expected FALSE for path '%s', got TRUE", path); path = "./api-tests"; res = file_exists2(p, path); fail_unless(res == TRUE, "Expected TRUE for path '%s', got FALSE", path); } END_TEST START_TEST (gmtime_test) { struct tm *res; time_t now; mark_point(); res = pr_gmtime(NULL, NULL); fail_unless(res == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); time(&now); mark_point(); res = pr_gmtime(NULL, &now); #if defined(HAVE_GMTIME_R) fail_unless(res == NULL, "Failed to handle null pool"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); #else fail_unless(res != NULL, "Failed to handle %lu: %s", (unsigned long) now, strerror(errno)); #endif /* HAVE_GMTIME_R */ mark_point(); res = pr_gmtime(p, &now); fail_unless(res != NULL, "Failed to handle %lu: %s", (unsigned long) now, strerror(errno)); } END_TEST START_TEST (localtime_test) { struct tm *res; time_t now; mark_point(); res = pr_localtime(NULL, NULL); fail_unless(res == NULL, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); time(&now); mark_point(); res = pr_localtime(NULL, &now); #if defined(HAVE_LOCALTIME_R) fail_unless(res == NULL, "Failed to handle null pool"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); #else fail_unless(res != NULL, "Failed to handle %lu: %s", (unsigned long) now, strerror(errno)); #endif /* HAVE_LOCALTIME_R */ mark_point(); res = pr_localtime(p, &now); fail_unless(res != NULL, "Failed to handle %lu: %s", (unsigned long) now, strerror(errno)); } END_TEST START_TEST (strtime_test) { const char *res; time_t now; mark_point(); now = 0; res = pr_strtime(now); #if defined(HAVE_LOCALTIME_R) fail_unless(res == NULL, "Failed to handle null pool"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); #else fail_unless(res != NULL, "Failed to convert time %lu: %s", (unsigned long) now, strerror(errno)); #endif /* HAVE_LOCALTIME_R */ } END_TEST START_TEST (strtime2_test) { const char *res; char *expected; time_t now; mark_point(); now = 0; expected = "Thu Jan 01 00:00:00 1970"; res = pr_strtime2(now, TRUE); #if defined(HAVE_GMTIME_R) fail_unless(res == NULL, "Failed to handle null pool"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); #else fail_unless(res != NULL, "Failed to convert time %lu: %s", (unsigned long) now, strerror(errno)); fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected, res); #endif /* HAVE_GMTIME_R */ } END_TEST START_TEST (strtime3_test) { const char *res; char *expected; time_t now; mark_point(); now = 0; #if defined(HAVE_GMTIME_R) res = pr_strtime3(NULL, now, TRUE); fail_unless(res == NULL, "Failed to handle null pool argument"); fail_unless(errno == EINVAL, "Expected EINVAL (%s), got %s (%d)", strerror(EINVAL), strerror(errno), errno); #endif /* HAVE_GMTIME_R */ mark_point(); expected = "Thu Jan 01 00:00:00 1970"; res = pr_strtime3(p, now, TRUE); fail_unless(res != NULL, "Failed to convert time %lu: %s", (unsigned long) now, strerror(errno)); fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected, res); } END_TEST START_TEST (timeval2millis_test) { int res; struct timeval tv; uint64_t ms; res = pr_timeval2millis(NULL, NULL); fail_unless(res < 0, "Failed to handle null arguments"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = pr_timeval2millis(&tv, NULL); fail_unless(res < 0, "Failed to handle null millis argument"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); tv.tv_sec = tv.tv_usec = 0; res = pr_timeval2millis(&tv, &ms); fail_unless(res == 0, "Failed to convert timeval to millis: %s", strerror(errno)); fail_unless(ms == 0, "Expected 0 ms, got %lu", (unsigned long) ms); } END_TEST START_TEST (gettimeofday_millis_test) { int res; uint64_t ms; res = pr_gettimeofday_millis(NULL); fail_unless(res < 0, "Failed to handle null argument"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); ms = 0; res = pr_gettimeofday_millis(&ms); fail_unless(res == 0, "Failed to get current time ms: %s", strerror(errno)); fail_unless(ms > 0, "Expected >0, got %lu", (unsigned long) ms); } END_TEST START_TEST (snprintf_test) { char *buf; size_t bufsz; int res, expected; res = pr_snprintf(NULL, 0, NULL); fail_unless(res < 0, "Failed to handle null buffer"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); bufsz = 1; buf = palloc(p, bufsz); res = pr_snprintf(buf, 0, NULL); fail_unless(res < 0, "Failed to handle null format"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = pr_snprintf(buf, 0, "%d", 0); fail_unless(res == 0, "Failed to handle zero-length buffer"); res = pr_snprintf(buf, bufsz, "%d", 0); fail_unless(res < 0, "Failed to handle too-small buffer"); fail_unless(errno == ENOSPC, "Expected ENOSPC (%d), got %s (%d)", ENOSPC, strerror(errno), errno); res = pr_snprintf(buf, bufsz, "%s", "foobar"); fail_unless(res < 0, "Failed to handle too-small buffer"); fail_unless(errno == ENOSPC, "Expected ENOSPC (%d), got %s (%d)", ENOSPC, strerror(errno), errno); bufsz = 32; buf = palloc(p, bufsz); expected = 6; res = pr_snprintf(buf, bufsz, "%s", "foobar"); fail_unless(res == expected, "Expected %d, got %d", expected, res); } END_TEST START_TEST (snprintfl_test) { char *buf; size_t bufsz; int res, expected; res = pr_snprintfl(NULL, -1, NULL, 0, NULL); fail_unless(res < 0, "Failed to handle null buffer"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); bufsz = 1; buf = palloc(p, bufsz); res = pr_snprintfl(NULL, -1, buf, 0, NULL); fail_unless(res < 0, "Failed to handle null format"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = pr_snprintfl(__FILE__, __LINE__, buf, 0, "%d", 0); fail_unless(res == 0, "Failed to handle zero-length buffer"); res = pr_snprintfl(__FILE__, __LINE__, buf, bufsz, "%d", 0); fail_unless(res < 0, "Failed to handle too-small buffer"); fail_unless(errno == ENOSPC, "Expected ENOSPC (%d), got %s (%d)", ENOSPC, strerror(errno), errno); res = pr_snprintfl(__FILE__, __LINE__, buf, bufsz, "%s", "foobar"); fail_unless(res < 0, "Failed to handle too-small buffer"); fail_unless(errno == ENOSPC, "Expected ENOSPC (%d), got %s (%d)", ENOSPC, strerror(errno), errno); bufsz = 32; buf = palloc(p, bufsz); expected = 6; res = pr_snprintfl(__FILE__, __LINE__, buf, bufsz, "%s", "foobar"); fail_unless(res == expected, "Expected %d, got %d", expected, res); } END_TEST START_TEST (path_subst_uservar_test) { const char *path = NULL, *res, *original, *expected; res = path_subst_uservar(NULL, NULL); fail_unless(res == NULL, "Failed to handle null pool"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = path_subst_uservar(p, NULL); fail_unless(res == NULL, "Failed to handle null path pointer"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); res = path_subst_uservar(p, &path); fail_unless(res == NULL, "Failed to handle null path"); fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL, strerror(errno), errno); original = expected = "somepathhere"; path = pstrdup(p, expected); mark_point(); res = path_subst_uservar(p, &path); fail_unless(res != NULL, "Failed to handle path '%s': %s", path, strerror(errno)); fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected, res); session.user = "user"; original = "/home/%u"; expected = "/home/user"; path = pstrdup(p, original); mark_point(); res = path_subst_uservar(p, &path); fail_unless(res != NULL, "Failed to handle path '%s': %s", path, strerror(errno)); fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected, res); session.user = "user"; original = "/home/%u["; expected = "/home/user["; path = pstrdup(p, original); mark_point(); res = path_subst_uservar(p, &path); fail_unless(res != NULL, "Failed to handle path '%s': %s", path, strerror(errno)); fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected, res); session.user = "user"; original = "/home/%u[]"; expected = "/home/user[]"; path = pstrdup(p, original); mark_point(); res = path_subst_uservar(p, &path); fail_unless(res != NULL, "Failed to handle path '%s': %s", path, strerror(errno)); fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected, res); session.user = "user"; original = "/home/users/%u[0]/%u[0]%u[1]/%u"; expected = "/home/users/u/us/user"; path = pstrdup(p, original); mark_point(); res = path_subst_uservar(p, &path); fail_unless(res != NULL, "Failed to handle path '%s': %s", path, strerror(errno)); fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected, res); /* Attempt to use an invalid index */ session.user = "user"; original = "/home/users/%u[a]/%u[b]%u[c]/%u"; expected = original; path = pstrdup(p, original); mark_point(); res = path_subst_uservar(p, &path); fail_unless(res != NULL, "Failed to handle path '%s': %s", path, strerror(errno)); fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected, res); /* Attempt to use an out-of-bounds index */ session.user = "user"; original = "/home/users/%u[0]/%u[-1]%u[1]/%u"; expected = original; path = pstrdup(p, original); mark_point(); res = path_subst_uservar(p, &path); fail_unless(res != NULL, "Failed to handle path '%s': %s", path, strerror(errno)); fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected, res); /* Attempt to use an out-of-bounds index */ session.user = "user"; original = "/home/users/%u[0]/%u[0]%u[4]/%u"; expected = original; path = pstrdup(p, original); mark_point(); res = path_subst_uservar(p, &path); fail_unless(res != NULL, "Failed to handle path '%s': %s", path, strerror(errno)); fail_unless(strcmp(res, expected) == 0, "Expected '%s', got '%s'", expected, res); } END_TEST Suite *tests_get_misc_suite(void) { Suite *suite; TCase *testcase; suite = suite_create("misc"); testcase = tcase_create("base"); tcase_add_checked_fixture(testcase, set_up, tear_down); tcase_add_test(testcase, schedule_test); tcase_add_test(testcase, get_name_max_test); tcase_add_test(testcase, dir_interpolate_test); tcase_add_test(testcase, dir_best_path_test); tcase_add_test(testcase, dir_canonical_path_test); tcase_add_test(testcase, dir_canonical_vpath_test); tcase_add_test(testcase, dir_readlink_test); tcase_add_test(testcase, dir_realpath_test); tcase_add_test(testcase, dir_abs_path_test); tcase_add_test(testcase, symlink_mode_test); tcase_add_test(testcase, symlink_mode2_test); tcase_add_test(testcase, file_mode_test); tcase_add_test(testcase, file_mode2_test); tcase_add_test(testcase, exists_test); tcase_add_test(testcase, exists2_test); tcase_add_test(testcase, dir_exists_test); tcase_add_test(testcase, dir_exists2_test); tcase_add_test(testcase, file_exists_test); tcase_add_test(testcase, file_exists2_test); tcase_add_test(testcase, safe_token_test); tcase_add_test(testcase, check_shutmsg_test); tcase_add_test(testcase, memscrub_test); tcase_add_test(testcase, getopt_reset_test); tcase_add_test(testcase, gmtime_test); tcase_add_test(testcase, localtime_test); tcase_add_test(testcase, strtime_test); tcase_add_test(testcase, strtime2_test); tcase_add_test(testcase, strtime3_test); tcase_add_test(testcase, timeval2millis_test); tcase_add_test(testcase, gettimeofday_millis_test); tcase_add_test(testcase, snprintf_test); tcase_add_test(testcase, snprintfl_test); tcase_add_test(testcase, path_subst_uservar_test); suite_add_tcase(suite, testcase); return suite; }