/*                                                               */
/* Physics 673 Computer Assignment #2                            */
/* Trevor Nickle                                                 */
/* November 20, 1996                                             */
/*                                                               */
/* Purpose                                                       */
/*                                                               */
/*         To create a program that will spawn a secondary       */
/*         Process.  Have this process terminate normally without*/
/*         Having the calling process terminate before hand.     */
/*         Once the orignal process has determined that the      */
/*         Child process has terminated then terminate the       */
/*         Parent process.  All zombie processes should be       */
/*         Included.                                             */
/*                                                               */
/* Variables                                                     */
/*                                                               */
/* STAT    Integer pointer that is used to satisfy the necessary */
/*         Requirements of the waitpid routine.                  */
/* T       Integer variable that stores the returned value from  */
/*         The fork routine.  T = 0 inside the child and         */
/*         T = Child Process ID # inside the parent              */
/* W       Integer variable that stores the returned value from  */
/*         A waitpid routine.  Equals process id if process is   */
/*         Alive.  Equals -1 if process is dead.                 */
/* PARENT  Integer value that stores the id of the parent        */
/* CHILD   Integer value that stores the id of the child         */          
/* PP      Integer value that stores status of the parent pipe   */
/* PC      Integer value that stores status of the child pipe    */
/* PIPEFD  2 Dimensional integer array that allows child to      */
/*         Talk to parent and parent to listen                   */
/* PIPEFD2 2 Dimensional integer array that allows parent to     */
/*         Talk to child and child to listen                     */
/* KID     Character pointer that records child's thoughts       */
/* MOM     Character pointer that records parent's thoughts      */
/* CHILDMSG Character array that stores child's actual message   */
/* PARENTMSG Character array that stores parent's actual message */
/* BUF     Integer that limits the length of message passed      */
/* NUMPASSED Integer stores number of charcters passed over pipes*/
/* NUMREAD Integer stores number of characters read over pipes   */
/*                                                               */
/* NOTICE  THE ROUTINE STRNCPY IS USED TO PICK A PIECE OF A      */
/*         LARGER STRING AND PASS IT.  THIS ENSURES THAT THE PIPE*/
/*         IS ACTUALLY PASSING INFORMATION SEEING THAT BOTH THE  */
/*         ORIGINAL STRINGS ARE KNOWN TO BOTH PROCESSES.  HENCE  */
/*         IT WOULD BE UNCLEAR WHETHER OR NOT THE PIPE ACTUALLY  */
/*         PASSED DATA WITHOUT USING SOME STRING MANIPULATION    */
/*         ROUTINE.                                              */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define BUF 13
#define MASK 0644

int main()
{

int myshmid;
int ff,fd;
int numpassed,numread;
int *stat;
int t,w,pp,pc,parent,child;
int pipefd[2],pipefd2[2];
char *kid = "Hey Battle Axe!\0";
char *mom = "Well I Never! You Little Jerk!\0";
char *kid2= "Oops Sorry Mom.\0";
char *mom2= "That's Better My Child.\0";
char childmsg[BUF],parentmsg[BUF];
char childmsg2[BUF],parentmsg2[BUF];
char *stupid = "./dumb.file";


printf("PARENT: This Program Creates A Child\n");
printf(" \n");
parent = getpid();
printf("PARENT: The Parent Process Id is %d\n",parent);
printf(" \n");
system("ps -l | grep a.out | grep -v grep"); /* Shows Parent is Alive */
printf(" \n");
printf("PARENT: A Child Will Now Be Born\n");
printf(" \n");
printf("PARENT: I remember the first words my child said to me\n");
printf("PARENT: They were intended to be %s\n",kid);
printf("PARENT: But that wasn't said - What was?  Find out soon!\n");
printf(" \n");


ff = mkfifo(stupid, MASK);
printf("PARENT: ff is %d\n",ff);
if (ff==-1) printf("PARENT: Waring! Fifo not created\n");
/* Above line checks to see that fifo created properly */
/* Infact it is this line that I spent all day yesterday */
/* trying to figure out.  Do you know why it will return */
/* -1 most times and 0 maybe 1 in 30??                   */

pp = pipe(pipefd);  /* Generates two pipes with pp and pc being */
pc = pipe(pipefd2); /* The respective flags of each pipe        */

printf("PARENT: pp = %d  %d  %d\n",pp,pipefd[0],pipefd[1]);
printf("PARENT: pc = %d  %d  %d\n",pc,pipefd[0],pipefd[1]);

if ((pp<0)||(pc<0)) {  /* Error Checking for pipe creation */      
   printf("PARENT: Error in creating pipes\n");
   exit(1);           
                    }
printf("PARENT: stupid is %s\n",stupid);
/* Above line checks that data file is known to process */

printf("PARENT: Both pipes are successfully created\n");
printf(" \n");

t = fork();  /* Child process is spawned here */

if (t<0) {   /* Error checking for successful fork execution */
    printf("PARENT: Miscarriage\n");
    exit(1);
         }

if (t==0) {  /* Child process executes only this part of the if */

/******************/
/* Part 2A        */
/*                */

  printf("CHILD: Child Born\n");
  printf("CHILD: Here I am!\n"); 
  printf(" \n");
  printf("CHILD: Sending Info To Mom\n");
  printf("CHILD: My Message is %s\n",strncpy(childmsg,kid,(BUF-3)));
  numpassed = write(pipefd[1],childmsg,(int)strlen(strncpy(childmsg,kid,(BUF-3))));
/* Above write statement tells parent child's thougths - 1st 10 */
/* Characters of the "kid" message                              */

  close(pipefd[1]); /* Closes Pipe for writing to parent */
  printf("CHILD: PIPE CLOSED FOR WRITING TO PARENT\n");
  printf("CHILD: numpassed is %d\n",numpassed);
  
  if (numpassed==-1) { /* Error Check for writing to pipe */
    printf("CHILD: Write Error!\n");
    exit(1);
                     }
  
  sleep(5);

  printf(" \n");
  printf("CHILD: I wonder what mom will say to that?\n");
  numread = read(pipefd2[0],childmsg,BUF); /* Reads from parent */
  close(pipefd2[0]); /* Closes pipe for reading from parent */
  printf("CHILD: PIPECLOSED FOR READING FROM PARENT\n");

  if (numread==-1) { /* Error check for reading from pipe */
    printf("CHILD: I didn't hear you Mom!\n");
    exit(1);
                   }

  printf("CHILD: Mom's Reply - %s\n",childmsg);

/*              */ 
/* Part 2A Ends */
/****************/
/* Part 2B      */
/*              */

sleep(10);

printf("CHILD: Entering part 2b\n");

fd = open(stupid,O_RDWR,0);
printf("CHILD: fd = %d\n",fd);

if (fd==-1) {
  printf("CHILD: Open statement incorrect #1\n");
  /*exit(1);*/
            }


printf("CHILD: My Message is %s\n",strncpy(childmsg2,kid2,(BUF-3)));

numpassed = write(fd,childmsg2,(int)strlen(strncpy(childmsg2,kid2,(BUF-3))));
close(fd);
printf("CHILD: Numpassed is %d\n",numpassed);
sleep(3);

printf("CHILD:  Waiting for parents reply\n");

fd = open(stupid,O_RDWR,0);
printf("CHILD: fd = %d\n",fd);

if (fd==-1) {
  printf("Open statement incorrect #2\n");
 /*exit(1);*/
            }

numread = read(fd,childmsg2,(BUF-3)); /* Reads from parent */

close(fd);
printf("CHILD: Closed fifo for reading\n");
if (numread==-1) {
  printf("CHILD: Error in read #3\n");
  /*exit(1); */
                 }
printf("CHILD: Parent's message is %s\n",childmsg);

/*              */
/* Part 2B Ends */
/****************/
/* Part 1       */
/*              */

  sleep(1);
  printf(" \n");
  child = getpid();
  printf("CHILD: My Process ID is %d\n",child);      
  printf(" \n");
  system("ps -l | grep a.out | grep -v grep"); /* Shows Parent & Child */
  printf(" \n");                                 /* Alive and well       */
  printf("CHILD: Life Sucks - I'm Going To Die Now\n");

         }  /* Child executions end here.  Child becomes a Zombie */

/*              */
/* Part 1 Ends  */
/****************/

  else {    /* Parent Executes Only This Part of the code */

/****************/
/* Part 2A      */
/*              */

    printf(" \n");
    numread = read(pipefd[0],parentmsg,(BUF-3)); /* Reads from child */
    printf("PARENT: numread = %d\n",numread);
    close(pipefd[0]); /* Closes pipe for reading from child */
    printf("PARENT: PIPE CLOSED FOR READING FROM CHILD\n");   

    if (numread==-1) { /* Error Check for reading from pipe */
      printf("PARENT: Read Error!\n");
      exit(1);
                     }
  
    printf("PARENT: What did my darling child say to me? %s\n",parentmsg);
    printf(" \n");
    printf("PARENT: This kid is mine???\n");
    printf("PARENT: %s - No better not say that.\n",mom);
    printf("PARENT: Instead... \n");
    printf("PARENT: %s\n",strncpy(parentmsg,mom,BUF));
    numpassed=write(pipefd2[1],parentmsg,(int)strlen(strncpy(parentmsg,mom,BUF)));
    
    /* Above write sends message to child */

    close(pipefd2[1]); /* Closes pipe for writing to child */
    printf("PARENT: PIPE CLOSED FOR WRITING TO CHILD\n");
    printf("PARENT: Number passed is %d\n",numpassed);
    sleep(10);

/*              */
/* Part 2A Ends */
/****************/
/* Part 2B      */
/*              */

sleep(10);
printf(" \n");
printf("PARENT: What did the child say this time?\n");
fd = open(stupid,O_RDWR,0);
if (fd==-1) {
  printf("PARENT: Open Error #4\n");
  /*exit(1);*/
            }
numread = read(fd,parentmsg2,(BUF-3)); /* Reads from child */
/* The above line needs to be commented out for the program to */
/* run to completion and see the zombie process                */
close(fd);
printf("PARENT: Read to fifo closed\n");
printf("PARENT: Numread is %d\n",numread);
printf("PARENT: Child's reply %s\n",parentmsg2);

printf("PARENT: Well this is what I think\n");

fd = open(stupid,O_RDWR,0);
if (fd==-1) {
  printf("PARENT: Open error #5\n");
  /*exit(1);*/
            }
printf("PARENT: My message is %s\n",strncpy(parentmsg2,kid2,(BUF-3)));
numpassed = write(fd,parentmsg2,(int)strlen(strncpy(parentmsg2,kid2,(BUF-3))));
close(fd);
printf("PARENT: Numpassed is %d\n",numpassed);
if (numpassed==-1) {
  printf("PARENT: Error in writing #6\n");
  /*exit(1);*/
                   }

/*              */
/* Part 2B Ends */
/****************/
/* Part 1       */
/*              */
    sleep(3);
    printf(" \n");
    system("ps -l | grep a.out | grep -v grep"); /* Shows Zombie Process */
    printf(" \n");
    printf("PARENT: Child Process %d Is A Zombie!\n",t);
    
    w = waitpid(t,stat,1);
    while (w!=-1) {  /* This While confirms that the child has died */
/*      printf("w is %d\n",w);*/
      w = waitpid(t,stat,1);
                  }  
                     /* Once parent is here, child is dead and removed */
                     /* Parent is now allowed to terminate             */
    printf(" \n");    
    printf("PARENT: Lets See What My Child Is Up To?\n");
    printf(" \n");
    system("ps -l | grep a.out | grep -v grep"); /* Shows only parent proc */
    printf(" \n");
    printf("PARENT: Child Process %d Is Dead And Removed - Time To Exit\n",t);
    printf(" \n");
       }

/*              */
/* Part 1 Ends  */
/****************/

return 0;
}