/*  Program: ass9b.c
    Compile command on OSF1: cc ass9bnew.c -lsys5
    Author: K. Martens
    Date:   Nov. 25/ 96 

  This is a program that generates an error on purpose by 
  trying to write to a place in memory that the program 
  should not write to. This will generate a SIGSEGV signal 
  that that program will catch and report.

 NEW* In the case that one does not consider an attempt 
    to write to an undesirable place in memory a hardware 
    execption, I will also include a signal trapping procedure
    for the SIGBUS signal. However, I cannot think of a way to 
    demonstrate this maybe execpt for providing a static hit
    to the processor or something else as drastic.

  This is the one of the categories of signals that is 
  specified in assignment 9. The other 4 categories of 
  signals that have to be caught are demonstrated in 
  ass9a.c . 
                               -Kalen          */

#include
#include
#include

main()
{
 int number;    /* Number to get from user and print out. */

 void signal_handler_SEGV( int sig ); /* Signal handler routine defintion */
 void signal_handler_BUS( int sig ); /* Signal handler routine defintion */

 signal( SIGSEGV, signal_handler_SEGV);
 signal( SIGBUS, signal_handler_BUS);

 printf("\nStart of Program!\n\n");

 /* Get a number from user and print it out */

 printf("\nType an integer and hit enter:");
 scanf("%d", &number);
 printf("\nYou typed the number %d.\n", number);

 printf("\n And now for something completely different....\n");

 /* This time, try to put the input in a completely undetermined place in 
    memory. This should generate the signal I want to catch. On some 
    machines, zero is a valid address and probably only exists because
    people (like me) can write programs that try to write there
    all the time. You might also be able to guess an address that 
    is also valid and either write something to &number (very lucky)
    or over other data the program has access to (takes a little less 
    luck, but still pretty hard.) 
    */ 

 printf("\nType an integer -not zero- and hit enter:");
 scanf("%d", number);
 printf("\nYou typed the number %d.\n", number);

 exit(0);      /* Terminate normally  - I know I won't make it here,
                                        but I could just pretend.  */
}



/* This is the routine that is run when the SEGV signal is caught. 
   
   This routine is written so that it              
   will not be able to be interupted in its execution: the signal
   that is caught will be temporarily ignored as the corresponding
   message is being printed.     */

void signal_handler_SEGV( int sig )
{
 signal( SIGSEGV, SIG_IGN);
 printf(" Caught a SIGSEGV signal, a hardware exception occured.\n");
 printf(" This seems like a good time to exit.\n");
 exit(-1);

}

/* This routine handles a bus error signal, SIGBUS. It will merely
   report the receipt of the signal and the program will exit with
   a non-zero status (-1 in this case). */

void signal_handler_BUS( int sig )
{
 signal( SIGBUS, SIG_IGN);
 printf(" Caught a SIGBUS signal, a hardware exception occured.\n");
 printf(" This seems like an even better time to exit.\n");
 exit(-1);

}

/*  Program: ass9a.c
    Compile command on OSF1: cc ass9a.c -lsys5
    Author: K. Martens
    Date:   Nov. 24/ 96 

   This is a simple program that forks off a child 
   process. The parent will stay in a loop waiting for 
   signal provided by the child and also from the 
   terminal. The child will provide the following 
   signals - a SIGTERM signal from a kill() function as 
   well as a SIGCHLD when the child exits (software condition).

   The parent will be able to catch SIGINTs generated 
   from a CNTL-C from the terminal, SIGTERM's generated 
   by the kill command (default with no options - is to send
   a SIGTERM signal), and the kill() library function also
   sending a SIGTERM signal. The behavior of the parent will
   be such that these signals will not able to stop execution 
   of the parent.

   The parent will periodically call waitpid() and see
   if the child has terminated. If it has, the parent will
   terminate as well.

   This program demonstrates signal catching from 4 of the 5
   categories required in assignment 9. Please see the companion 
   program ass9b.c for an example of a hardware execption 
   generated signal.   
                               -Kalen          */

#include
#include
#include
#include
#include

main()
{

 void signal_handler_INT( int sig );
 void signal_handler_TERM( int sig );
 void signal_handler_CHLD( int sig );


 pid_t ierr;         /* Variable for return value of fork()             */
 int dummy;          /* Variable to contain return value of waitpid()   
                        in parent and kill() in the child               */
 pid_t parent_pid;   /* PID of parent process                           */
 pid_t child_pid;    /* PID of child process                            */
 pid_t child_ppid;   /* PID of child's parent                           */

 unsigned int time_left;     /* Time left for parent to sleep */

 int *stat;          /* Status of wait function                         */

 printf("\nStart of Program!\n\n");

/* Find PID of this process and print it to screen. */

 parent_pid = getpid();
 printf("Before fork: Parent PID: %d\n", parent_pid);
 printf("Send a SIGTERM to me. Type: kill %d \n\n", parent_pid);

/* Execute the fork and complain on error  */

 if ( (ierr = fork()) < 0 ) {
    printf("Error on calling of fork()\n");
    exit(1); }                              
 else {
    printf("Fork succeeded.\n"); }         /* This will get written twice */
    
 /* Both processes now examine ierr (parent gets child's PID
    returned and child gets 0 returned from fork function)
    and decide if they are the parent or child. The child will
    also find the PID of its parent.             */

 if (ierr != 0) {                      /* I AM THE PARENT  */

    child_pid=ierr;

  /* Use the signal() function to declare which signals I want to catch
     and which functions to run when they are caught. */

    signal( SIGINT, signal_handler_INT);
    signal( SIGTERM, signal_handler_TERM);
    signal( SIGCHLD, signal_handler_CHLD);

    /* Wait for the child to terminate. Meanwhile, just wait
       and catch signals and print La de da every once in a 
       while. If sleep() does not get interupted by a signal,
       print La de da to show parent is still there. */

    do {
        time_left=sleep(2);
        if (time_left == 0 ) {
           printf("La de da.\n"); }
 
       } while ((dummy = waitpid(child_pid,stat,WNOHANG)) == 0); 
    printf("\n\nParent is still alive: PID: %d\n", parent_pid); 
    printf("Parent is now exiting.\n"); }

 else if ( ierr == 0 ) {                /* I AM THE CHILD  */

    /* Child should ignore a SIGINT (cntl-c) from the keyboard 
       and sleep enough so terminal generated signals can 
       be sent to the parent    */

    signal( SIGINT, SIG_IGN);

    child_pid = getpid();
    child_ppid = getppid();                    /* Get parent's PID   */
    sleep(15);

    printf("Child: Sending TERM signal to parent.\n");
    dummy = kill(child_ppid, SIGTERM);    /* Send TERM signal to parent */
    if (dummy != 0) {
      printf("Child: Sending TERM did not work- errno: %d\n", errno); }

    sleep(40);

    printf("Child process now exiting\n"); }

 exit(0);                                      /* Terminate normally   */
}



/* These are the routines that are run when the INT, TERM, and SIGCHLD
   signals are caught. These routines are written so that they themselves
   will not be able to be interupted in their execution: the signal
   that is caught will be temporarily ignored as the corresponding
   message is being printed.     */

void signal_handler_INT( int sig )
{
 signal( SIGINT, SIG_IGN);
 printf(" Caught a SIGINT signal, but you can't stop me!! HA HA HA\n");
 signal( SIGINT, signal_handler_INT);

}

void signal_handler_TERM( int sig )
{
 signal( SIGTERM, SIG_IGN);
 printf(" Caught a SIGTERM signal, but you can't stop me!! HA HA HA\n");
 signal( SIGTERM, signal_handler_TERM);

}

void signal_handler_CHLD( int sig )
{
 signal( SIGCHLD, SIG_IGN);
 printf(" Caught a SIGCHLD signal, child is terminating!!!\n");
 signal( SIGCHLD, signal_handler_CHLD);

}