/* 3000cp-fifo.c  Simple producer-consumer with a fifo
 * Original Version Copyright (C) 2026  Anil Somayaji
 *
 * 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 3 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, see <https://www.gnu.org/licenses/>. */

/* You really shouldn't be incorporating parts of this in any other code,
   it is meant for teaching, not production */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>

#define BUFSIZE 4096

void report_error(char *error)
{
        fprintf(stderr, "Error: %s\n", error);
}

void usage_exit(char *progname)
{
        fprintf(stderr,
                "Usage: %s <source file> <dest file>\n",
                progname);
        exit(-1);
}

void read_file(char *fn, int out_fd)
{
        char buf[BUFSIZE];
        int in_fd;
        ssize_t read_count, write_count;

        in_fd = open(fn, O_RDONLY);

        if (in_fd == -1) {
                report_error("Couldn't open file for reading\n");
                close(out_fd);
                exit(-1);
        }

        while ((read_count = read(in_fd, buf, BUFSIZE)) > 0) {
                write_count = write(out_fd, buf, read_count);
                if (write_count != read_count) {
                        report_error("Problem sending data to writer.");
                        close(out_fd);
                        exit(-1);
                }
        }

        close(in_fd);
        close(out_fd);
        printf("File successfully read and sent.\n");
        exit(0);
}

void write_file(char *fn, int in_fd)
{
        char buf[BUFSIZE];
        int out_fd;
        ssize_t read_count, write_count;

        out_fd = creat(fn, 0666);

        if (out_fd == -1) {
                report_error("Couldn't open file for writing\n");
                close(in_fd);
                exit(-1);
        }

        while ((read_count = read(in_fd, buf, BUFSIZE)) > 0) {
                write_count = write(out_fd, buf, read_count);
                if (write_count != read_count) {
                        report_error("Problem writing file to disk.");
                        exit(-1);
                }
        }

        close(in_fd);
        close(out_fd);
        printf("File successfully received and copied.\n");
        exit(0);
}

int main(int argc, char *argv[])
{
        int pid;
        int pipefd[2];
        char *source_fn, *dest_fn;

        if (argc < 3) {
                if (argc < 2) {
                        report_error("no command line");
                        usage_exit(argv[0]);
                } else {
                        report_error("Not enough arguments");
                        usage_exit(argv[0]);
                }
        }
        
        source_fn = argv[1];
        dest_fn = argv[2];

        if (pipe(pipefd)) {
                report_error("Unable to open pipe");
                exit(-1);
        }
        
        pid = fork();
        
        if (pid == 0) {
                close(pipefd[0]);
                read_file(source_fn, pipefd[1]);
        } else {
                close(pipefd[1]);
                write_file(dest_fn, pipefd[0]);
        }

        return -1;
}
