SICE Curriculum Portal for Thomas Heffron
Contents

Home
UMKC Curriculum
   FS '96
      CS 101
   SS '01
      CS 201
   FS '01
      CS 191
      CS 281
   WS '02
      CS 291
      EN 304wi
   SS '02
      CS 352
      CS 481
   FS '02
      CS 431
      CS 441
   WS '03
      CS 423
      CS 451
SICE Survival Guide
Personal Experience

contact me @umkc:
tehqnf@umkc.edu

CS431 - Homework #6
 
/******************************************
Name:     Thomas Heffron
Section:  CS431 NET
Program:  Program #6 - main
Due Date: Dec. 5, 2002
Desc:     Write a program that spawns three
          processes that pass information
          'down the line' from one to another.
          It will do this using IPC pipes.
Inputs:   CMD arguments given for length of
          time that main process will run.
          Can also take arguments for input
          and output files.
Outputs:  Show pipe and thread creation.
          After 'encrypt' and 'decrypt' of
          input string, output original string
          to display AND output file.
******************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <wait.h>
#include <errno.h>

extern char **environ;
extern int errno;

/* Type definitions used by all functions */
int proc_duration;

/* Input and output streams */
char in_file[50];
char in_fil_pipe[50] = "in_fil";
char fil_out_pipe[50] = "fil_out";
char out_file[50];

/* Process ID numbers */
pid_t pro_pid, fil_pid, con_pid;

/* Arrays to hold arguments */
char *pro_args[3];
char *fil_args[3];
char *con_args[3];

/* Function declarations */
static void sig_alarm(int signo);
int check_args(int num, char *input[]);

int main(int argc, char *argv[])
{
    /* Variable declarations */
    time_t now;
    int fifostat;

    /* Parse and check the args passed to the program */
    if ( check_args(argc, argv) ) {

        /* Set alarm signal handler */
        if (signal(SIGALRM, sig_alarm) == SIG_ERR) {
            printf("The signal function returned an error\n");
            exit(1);
        }

        /* Now, set alarm */
        alarm(proc_duration);

        /* Create fifo pipe between producer and filter */
        /* Exit on error unless that pipe name already exists */
        fifostat = mkfifo(in_fil_pipe, 0666);
        if (fifostat < 0) {
            if (errno != EEXIST) {
                printf("!!! Could not create pipe: in_fil\n");
                printf("!!! Exiting process.\n");
                exit(1);
            }
        }

        /* Create fifo pipe between filter and consumer */
        /* Exit on error unless that pipe name already exists */
        fifostat = mkfifo(fil_out_pipe, 0666);
        if (fifostat < 0) {
            if (errno != EEXIST) {
                printf("!!! Could not create pipe: fil_out\n");
                printf("!!! Exiting process.\n");
                exit(1);
            }
        }

        /* Create arg array for producer and fork new process */
        pro_args[0] = "./producer";
        pro_args[1] = in_file;
        pro_args[2] = in_fil_pipe;
        pro_pid = fork();
        if (pro_pid == 0) { /* Exec on fork and catch errors */
            if (execve(pro_args[0], pro_args, environ) == -1) {
                printf("ERROR IN EXECVE ");
                perror("execve");
            }
        }

        /* Create arg array for filter and fork new process */
        fil_args[0] = "./filter";
        fil_args[1] = in_fil_pipe;
        fil_args[2] = fil_out_pipe;
        fil_pid = fork();
        if (fil_pid == 0) { /* Exec on fork and catch errors */
            if(execve(fil_args[0], fil_args, environ) == -1) {
                printf("ERROR IN EXECVE ");
                perror("execve");
            }
        }

        /* Create arg array for consumer and fork new process */
        con_args[0] = "./consumer";
        con_args[1] = fil_out_pipe;
        con_args[2] = out_file;
        con_pid = fork();
        if (con_pid == 0) { /* Exec on fork and catch errors */
            if (execve(con_args[0], con_args, environ) == -1) {
                printf("ERROR IN EXECVE ");
                perror("execve");
            }
        }

        /* Now wait/sleep until alarm calls to continue */
        while(1) {
             sleep(1);
        }
    } else {
        /* If arguments do not parse display correct usage and exit */
        printf("Usage: %s num_procs [-i in_file] [-o out_file]\n", argv[0]);
        exit(1);
    }
}

/* Function to handle alarm */
static void sig_alarm(int signo)
{
    alarm(0); /* reset alarm and display messages */
    printf("\n*** Alarm to end process ***\n");
    printf("*** Now cleaning up threads ***\n\n");

    /* Now signal all spawned processes to halt */
    kill(con_pid, SIGUSR1);
    kill(fil_pid, SIGUSR1);
    kill(pro_pid, SIGUSR1);

    /* Wait one second for all processes to halt */
    /* This makes for cleaner looking exit */
    sleep(1);
    printf("\n");

    /* Now signal all spawned processes to exit in reverse of */
    /* creation order and wait for each process to exit before */
    /* continuing to next kill call - again for cleaner look */
    /* We dont want to close the writer before closing the reader */
    kill(con_pid, SIGUSR2);
    waitpid(con_pid, NULL, 0);
    kill(fil_pid, SIGUSR2);
    waitpid(fil_pid, NULL, 0);
    kill(pro_pid, SIGUSR2);
    waitpid(pro_pid, NULL, 0);

    /* Now send notice of process conclusion */
    printf("\n*** Main process now exiting\n");
    exit(0);
}

/* Function to parse and check arguments passed to process */
int check_args(int num, char *input[]) {
    if (num < 2) {
        /* return false if less than no args passed */
        return 0;
    } else if (num == 2) {
        /* set alarm timer and default files */
        proc_duration = atoi(input[1]);
        strcpy(in_file, "input.txt");
        strcpy(out_file, "output.txt");
    } else if (num == 4) {
        /* set alarm timer and one default file */
        /* check flag of file passed in (input or output) */
        /* return false if flag is bad */
        proc_duration = atoi(input[1]);
        if ( strcmp(input[2], "-i") == 0 ) {
            strcpy(in_file, input[3]);
            strcpy(out_file, "output.txt");
        } else if ( strcmp(input[2], "-o") == 0 ) {
            strcpy(in_file, "input.txt");
            strcpy(out_file, input[3]);
        } else {
            return 0;
        }
    } else if (num == 6) {
        /* set alarm timer and both files */
        /* must check order of input */
        /* return false if flag error */
        proc_duration = atoi(input[1]);
        if ( strcmp(input[2], "-i") == 0 ) {
            if ( strcmp(input[4], "-o") == 0) {
                strcpy(in_file, input[3]);
                strcpy(out_file, input[5]);
            } else {
                return 0;
            }
        } else if ( strcmp(input[2], "-o") == 0 ) {
            if ( strcmp(input[4], "-i") == 0) {
                strcpy(in_file, input[5]);
                strcpy(out_file, input[3]);
            } else {
                return 0;
            }
        } else {
            return 0;
        }
    } else {
        /* return false if number of args is not one of above */
        return 0;
    }

    /* display settings from args before returning success */
    printf("Setting alarm for %d seconds.\n", proc_duration);
    printf("Setting input file to: %s\n", in_file);
    printf("Setting output file to: %s\n\n", out_file);
    return 1;
}