summaryrefslogblamecommitdiff
path: root/pgm3/report.c
blob: 623de6fbc26eb77953a8824f04d738d42c5a2bf5 (plain) (tree)







































































































































































































































                                                                                      
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <unistd.h>

#define FALSE 0
#define FILE_BUFF 4096
#define TRUE  1

int terminateFlag = 1; // Used with signal handler function.

void sigHandler(int signum) {
    /*
     * sigHandler() waits for a SIGUSR1 signal. Upon receiving this signal it
     * decrements terminateFlag, lowering it to zero.
     */

    if (signum == SIGUSR1) {
        terminateFlag--;
    }

}

int main(int argc, char *argv[]) {
    /*
     * report takes in one required argument ("num") and two optional arguments.
     * -k specifies that output should be printed in kilobytes, not bytes
     * -d specifies a delay that should be waited before reading each filename
     * into the totalsize child process.
     *
     * Report takes in filenames on its stdin and then calls four child
     * processes. Two execute accessed, one with num as an arg and one with
     * -num as an arg. report writes its stdin to the stdin of the accessed
     * children. The accessed children then print their output to the stdin
     * of two more children that execute totalsize. These totalsize
     * children run through the filenames they're given and print out the
     * size of those files back into report. This is all done via pipes.
     *
     * report then prints out the results it receives from its children.
     */
    char byteSum[10];
    char delayStr[10];
    char *envar = NULL;
    char filename[FILE_BUFF];
    char numNeg[11];
    char thisPID[10];
    int accessedNum;
    int delay = 0;
    int i = 2;

    // Go through args.
    if (argc < 2) {
        fprintf(stderr, "usage: ./report [num days] {-k} {-d} [delay]\n");
        exit(1);
    }

    // Fetch accessedNum parameter
    accessedNum = strtol(argv[1], NULL, 10);
    errno = 0;

    if (accessedNum <= 0) {
        fprintf(stderr, "report: num must be positive, nonzero integer.\n");
        exit(1);
    }
    else if (errno == ERANGE) {
        fprintf(stderr, "report: num must be of integer size.\n");
        exit(1);
    }
    else if (errno == EINVAL) {
        fprintf(stderr, "report: num must be integer type.\n");
        exit(1);
    }

    // Set the second accessed num as negative.
    sprintf(numNeg, "%d", accessedNum * -1);

    while (argv[i]) {

        if (strcmp(argv[i], "-k") == 0) {
            setenv("UNITS", "k", 1);
        }
        else if (strcmp(argv[i], "-d") == 0) {
            delay = strtol(argv[i+1], NULL, 10);
            errno = 0;

            if (delay <= 0) {
                fprintf(stderr, "report: delay must be positive, nonzero integer.\n");
                exit(1);
            }
            else if (errno == ERANGE) {
                fprintf(stderr, "report: delay must be of integer size.\n");
                exit(1);
            }
            else if (errno == EINVAL) {
                fprintf(stderr, "report: delay must be integer type.\n");
                exit(1);
            }

            sprintf(delayStr, "%d", delay);
            setenv("TSTALL", delayStr, 1);
            i++;
        }
        else {
            fprintf(stderr, "usage: ./report [num days] {-k} {-d} [delay]\n");
            exit(1);
        }

        i++;
    }

    // Set up signal handling.
    sprintf(thisPID, "%d", getpid());
    setenv("TMOM", thisPID, 1);
    signal(SIGUSR1, sigHandler);

    // Set up pipes.
    int pipeRtoA1[2]; pipe(pipeRtoA1);
    int pipeRtoA2[2]; pipe(pipeRtoA2);
    int pipeA1toT1[2]; pipe(pipeA1toT1);
    int pipeA2toT2[2]; pipe(pipeA2toT2);
    int pipeT1toR[2]; pipe(pipeT1toR);
    int pipeT2toR[2]; pipe(pipeT2toR);

    if (fork() == 0) { // accessed 1
        // Close unneeded pipes =====================
                                close(pipeRtoA1[1]);
        close(pipeRtoA2[0]);    close(pipeRtoA2[1]);
        close(pipeA1toT1[0]);
        close(pipeA2toT2[0]);   close(pipeA2toT2[1]);
        close(pipeT1toR[0]);    close(pipeT1toR[1]);
        close(pipeT2toR[0]);    close(pipeT2toR[1]);
        // ==========================================

        // Dup read end to stdin and write end to stdout
        close(0); dup(pipeRtoA1[0]); close(pipeRtoA1[0]);
        close(1); dup(pipeA1toT1[1]); close(pipeA1toT1[1]);
        execl("accessed", "accessed", argv[1], NULL);
    }
    else if (fork() == 0) { // accessed 2
        // Close unneeded pipes =====================
        close(pipeRtoA1[0]);    close(pipeRtoA1[1]);
                                close(pipeRtoA2[1]);
        close(pipeA1toT1[0]);   close(pipeA1toT1[1]);
        close(pipeA2toT2[0]);
        close(pipeT1toR[0]);    close(pipeT1toR[1]);
        close(pipeT2toR[0]);    close(pipeT2toR[1]);
        // ==========================================

        close(0); dup(pipeRtoA2[0]); close(pipeRtoA2[0]);
        close(1); dup(pipeA2toT2[1]); close(pipeA2toT2[1]);
        execl("accessed", "accessed", numNeg, NULL);
    }
    else if (fork() == 0) { // totalsize 1
        // Close unneeded pipes =====================
        close(pipeRtoA1[0]);    close(pipeRtoA1[1]);
        close(pipeRtoA2[0]);    close(pipeRtoA2[1]);
                                close(pipeA1toT1[1]);
        close(pipeA2toT2[0]);   close(pipeA2toT2[1]);
        close(pipeT1toR[0]);
        close(pipeT2toR[0]);    close(pipeT2toR[1]);
        // ==========================================

        close(0); dup(pipeA1toT1[0]); close(pipeA1toT1[0]);
        close(1); dup(pipeT1toR[1]); close(pipeT1toR[1]);
        execl("totalsize", "totalsize", NULL);
    }
    else if (fork() == 0) { // totalsize 2
        // Close unneeded pipes =====================
        close(pipeRtoA1[0]);    close(pipeRtoA1[1]);
        close(pipeRtoA2[0]);    close(pipeRtoA2[1]);
        close(pipeA1toT1[0]);   close(pipeA1toT1[1]);
                                close(pipeA2toT2[1]);
        close(pipeT1toR[0]);    close(pipeT1toR[1]);
        close(pipeT2toR[0]);
        // ==========================================

        close(0); dup(pipeA2toT2[0]); close(pipeA2toT2[0]);
        close(1); dup(pipeT2toR[1]); close(pipeT2toR[1]);
        execl("totalsize", "totalsize", NULL);
    }

    // Close those pipes which parent report does not need
    close(pipeRtoA1[0]);
    close(pipeRtoA2[0]);
    close(pipeA1toT1[0]);   close(pipeA1toT1[1]);
    close(pipeA2toT2[0]);   close(pipeA2toT2[1]);
                            close(pipeT1toR[1]);
                            close(pipeT2toR[1]);

    // Write stdin from report to accessed children
    while (scanf("%s", filename) == 1) {
        write(pipeRtoA1[1], strcat(filename, " "), strlen(filename) + 1);
        write(pipeRtoA2[1], strcat(filename, " "), strlen(filename) + 1);
    }

    // Close remaining pipes.
    close(pipeRtoA1[1]);    close(pipeRtoA2[1]);

    // Enter non-terminating loop to wait for children
    while (terminateFlag) {
        printf("*");
        sleep(1);
    }

    // Print results of first totalsize child
    read(pipeT1toR[0], byteSum, sizeof(byteSum)); close(pipeT1toR[0]);
    sscanf(byteSum, " %s ", byteSum);
    printf("\nA total of %s ", byteSum);

    if ((envar = getenv("UNITS")) == NULL || !(envar[0] != 'k' || envar[0] != 'K')) {
        printf("bytes ");
    }

    printf("are in regular files not accessed for %s days.\n----------\n", argv[1]);

    // Print results of second totalsize child
    read(pipeT2toR[0], byteSum, sizeof(byteSum)); close(pipeT2toR[0]);
    sscanf(byteSum, " %s ", byteSum);
    printf("A total of %s ", byteSum);

    if ((envar = getenv("UNITS")) == NULL || !(envar[0] != 'k' || envar[0] != 'K')) {
        printf("bytes ");
    }

    printf("are in regular files accessed within %s days.\n\n", argv[1]);
    exit(0);
}