bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen#include "test-lib.h"
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen#include "unlink-directory.h"
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen#include "file-create-locked.h"
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen#include <fcntl.h>
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen#include <signal.h>
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen#include <sys/stat.h>
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainenstatic void create_file(const char *path)
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen{
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen int fd;
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen fd = creat(path, 0600);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen if (fd == -1)
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen i_fatal("creat(%s) failed: %m", path);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen i_close_fd(&fd);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen}
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainenstatic bool wait_for_file(pid_t pid, const char *path)
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen{
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen struct stat st;
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen for (unsigned int i = 0; i < 1000; i++) {
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen if (stat(path, &st) == 0)
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen return TRUE;
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen if (errno != ENOENT)
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen i_fatal("stat(%s) failed: %m", path);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen if (kill(pid, 0) < 0) {
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen if (errno == ESRCH)
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen return FALSE;
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen i_fatal("kill(SIGSRCH) failed: %m");
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen }
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen usleep(10000);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen }
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen i_error("%s isn't being created", path);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen return FALSE;
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen}
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainenstatic void test_file_create_locked_basic(void)
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen{
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen struct file_create_settings set = {
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen .lock_timeout_secs = 0,
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen .lock_method = FILE_LOCK_METHOD_FCNTL,
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen };
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen const char *path = ".test-file-create-locked";
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen struct file_lock *lock;
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen const char *error;
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen bool created;
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen pid_t pid;
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen int fd;
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen test_begin("file_create_locked()");
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen i_unlink_if_exists(path);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen i_unlink_if_exists(".test-temp-file-create-locked-child");
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen pid = fork();
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen switch (pid) {
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen case (pid_t)-1:
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen i_error("fork() failed: %m");
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen break;
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen case 0:
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen /* child */
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen fd = file_create_locked(path, &set, &lock, &created, &error);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen test_assert(fd > 0);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen test_assert(created);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen if (test_has_failed())
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen exit(1);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen create_file(".test-temp-file-create-locked-child");
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen sleep(60);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen i_close_fd(&fd);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen exit(0);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen default:
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen /* parent */
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen test_assert(wait_for_file(pid, ".test-temp-file-create-locked-child"));
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen if (test_has_failed())
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen break;
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen test_assert(file_create_locked(path, &set, &lock, &created, &error) == -1);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen test_assert(errno == EAGAIN);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen if (kill(pid, SIGKILL) < 0)
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen i_error("kill(SIGKILL) failed: %m");
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen break;
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen }
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen i_unlink_if_exists(".test-temp-file-create-locked-child");
739bebfce2db4131cc137dafef0a796292fbf0d7Timo Sirainen i_unlink_if_exists(path);
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen test_end();
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen}
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainenstatic void test_file_create_locked_mkdir(void)
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen{
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen struct file_create_settings set = {
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen .lock_timeout_secs = 0,
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen .lock_method = FILE_LOCK_METHOD_FCNTL,
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen };
739bebfce2db4131cc137dafef0a796292fbf0d7Timo Sirainen const char *path;
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen struct file_lock *lock;
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen const char *error, *dir;
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen bool created;
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen int fd;
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen test_begin("file_create_locked() with mkdir");
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen dir = ".test-temp-file-create-locked-dir";
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen if (unlink_directory(dir, UNLINK_DIRECTORY_FLAG_RMDIR, &error) < 0)
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen i_fatal("unlink_directory(%s) failed: %s", dir, error);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen path = t_strconcat(dir, "/lockfile", NULL);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen /* try without mkdir enabled */
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen test_assert(file_create_locked(path, &set, &lock, &created, &error) == -1);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen test_assert(errno == ENOENT);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen /* try with mkdir enabled */
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen set.mkdir_mode = 0700;
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen fd = file_create_locked(path, &set, &lock, &created, &error);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen test_assert(fd > 0);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen test_assert(created);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen i_close_fd(&fd);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen struct stat st;
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen if (stat(dir, &st) < 0)
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen i_error("stat(%s) failed: %m", dir);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen test_assert((st.st_mode & 0777) == 0700);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen i_unlink(path);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen file_lock_free(&lock);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen if (unlink_directory(dir, UNLINK_DIRECTORY_FLAG_RMDIR, &error) < 0)
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen i_fatal("unlink_directory(%s) failed: %s", dir, error);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen test_end();
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen}
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainenvoid test_file_create_locked(void)
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen{
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen test_file_create_locked_basic();
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen test_file_create_locked_mkdir();
9a18972285665fc8ce3709f444f0f1e72e8b71a7Timo Sirainen}