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;
}