/// This test makes sure writing to the same file, when referred to
/// by multiple FDs (some of which are shared), works correctly. The
/// trace logs generated by Wasmer are also inspected to make sure
/// the file is closed properly.

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

void error_exit(const char *message)
{
    perror(message);
    exit(-1);
}

int main(int argc, char *argv[])
{
    int fd1 = open("./output", O_CREAT | O_EXCL | O_WRONLY);
    if (fd1 < 0)
    {
        error_exit("open");
    }

    int fd2 = dup(fd1);
    if (fd2 < 0 || fd2 == fd1)
    {
        error_exit("parent dup");
    }

    if (!write(fd2, "parent 2\n", 9))
    {
        error_exit("parent write 2");
    }

    pid_t pid = fork();
    if (pid == -1)
    {
        error_exit("fork");
    }
    else if (pid == 0)
    {
        if (close(fd2))
        {
            error_exit("child close parent fd2");
        }

        fd2 = dup(fd1);
        if (fd2 < 0 || fd2 == fd1)
        {
            error_exit("child dup");
        }

        if (!write(fd1, "child 1\n", 8))
        {
            error_exit("child write 1");
        }
        if (close(fd1))
        {
            error_exit("child close 1");
        }

        if (!write(fd2, "child 2\n", 8))
        {
            error_exit("child write 2");
        }
        if (close(fd2))
        {
            error_exit("child close 2");
        }
        exit(0);
    }
    else
    {
        if (close(fd2))
        {
            error_exit("parent close 2");
        }

        int status;
        waitpid(pid, &status, 0);
        if (status)
        {
            error_exit("child exit code");
        }

        if (!write(fd1, "parent 1\n", 9))
        {
            error_exit("parent write 1");
        }

        // These prints can be inspected to make sure the file was
        // closed as a result of the last close() call, see run.sh
        printf("closing last fd\n");
        if (close(fd1))
        {
            error_exit("parent close 1");
        }
        printf("last fd closed\n");
    }
}