/******************************************************************/
/* sig is a program which demonstrates the effects of trapping    */
/* 5 different types of signal using the signal function          */
/* This should work on any system but was tested on HPUX 9        */
/*                                                                */
/* Physics 673: Real Time Computing                               */
/* Norm Buchanan           96/11/26                               */
/******************************************************************/

#include 
#include 
#include 
#include 
#include 

#define TRUE 1
char nkill[9] = {'k','i','l','l',' ','-','1',' ','\0'};
int level=0;

void bus_kill(void);
void term_kill(void);
void kill_one(void);
void kill_two(void);
void soft_sig(void);
void itoa(int pid, char id[]);
void menu(void);
void sig_handle(int);

main () {

    menu();  /* Let the games begin */

}

/****************************************************************/
/* Trap the keyboard interrupt signal                           */
/****************************************************************/

void term_kill(void){

    if( signal(SIGINT, sig_handle) == SIG_ERR) {
	printf("\aError handling SIGINT signal\n");
	exit(1);
    }

    printf("Enter the ^C sequence to trap signal\n");
    pause();  /* wait for a signal */
    printf("Returning gracefully to term_kill routine and exiting normally\n");
}

/*****************************************************************/
/* Trap a hardware exception (bus error)                         */
/*****************************************************************/

void bus_kill(void){
  
  int ret_val;

  if( signal(SIGBUS, sig_handle) == SIG_ERR) {
    printf("\aError handling SIGFPE signal\n");
    exit(1);
  }
  
    ret_val = fork();
    if (ret_val == -1){  /* no child process forked */
	printf("\a::Error--Unsuccessful fork::");
	exit(1);
    }
    else if (ret_val == 0){  /* child hangs out*/
      sleep(100);
      printf("Returning gracefully to bus_kill routine and exiting normally\n");
    }
    else { /* parent sends child SIGBUS signal */
	sleep(2);
	kill(ret_val, SIGBUS);
    }
}

/*****************************************************************/
/* Trap a HUP signal sent to the child process via the system    */
/* kill call                                                     */
/*****************************************************************/

void kill_one(void){

    int ret_val, syscall;
    char id[9], *k;

    if( signal(SIGHUP, sig_handle) == SIG_ERR) {
	printf("\aError handling SIGHUP signal\n");
	exit(1);
    }

    k = nkill;

    ret_val = fork();
    if (ret_val == -1){  /* no child process forked */
	printf("\a::Error--Unsuccessful fork::");
	exit(1);
    }
    else if (ret_val == 0){  /* child waits around */
	sleep(100);
	printf("Returning to child process in kill_one and exiting normally\n");
    }
    else { /* parent sends child HUP signal */
	itoa(ret_val, id); /* convert integer to ascii */
        k = strcat(k, id); /* create appropriate kill command */ 
	syscall = system(k);
    }
}

/************************************************************************/
/* Use the C kill routine to send user defined signal to child for      */
/* trapping                                                             */
/************************************************************************/

void kill_two(void){

    int ret_val;
    
    if( signal(SIGUSR1, sig_handle) == SIG_ERR) {
	printf("\aError handling SIGUSR1 signal\n");
	exit(1);
    }

    ret_val = fork();
    if (ret_val == -1){  /* no child process forked */
	printf("\a::Error--Unsuccessful fork::");
	exit(1);
    }
    else if (ret_val == 0){  /* child hangs out */
	sleep(100);
	printf("Returning to child in kill_two and exiting normally\n");
    }
    else { /* parent sends child USR1 signal */
	kill(ret_val, SIGUSR1);
    }
}

/***************************************************************************/
/* Trap software exception (child terminated signal -- SIGCHLD)            */
/***************************************************************************/

void soft_sig(void){

    int ret_val;
    
    if( signal(SIGCHLD, sig_handle) == SIG_ERR) {
      printf("\aError handling SIGCHLD signal\n");
      exit(1);
    }

    ret_val = fork();
    if (ret_val == -1){  /* no child process forked */
	printf("\a::Error--Unsuccessful fork::");
	exit(1);
    }
    else if (ret_val == 0){  /* child hangs out */
	sleep(2);
    }
    else { /* parent waits for SIGCHLD signal */
	pause();
	printf("Back in parent process of soft_sig routine exiting normally\n");
    }
}


/**********************************************************/
/* A nifty little utility function shamefully taken from  */
/* "The C Programming Language" by Kernighan and Ritchie  */
/* which converts an integer to a character string        */
/**********************************************************/

void itoa (int pid, char id[]) { 
    
    int i=0, j, k, temp;
    
    do {  /* generate digits in reverse order */
	id[i++] = pid % 10 + '0';  /* get next digit */
    } while (( pid /= 10) > 0);
    id[i] = '\0';
     
    /* Now reverse the string */

    for (j=0, k = strlen(id)-1; j");

  scanf("%d", &choice);

  if (choice == 1) {
      printf("\n\nRunning machine exception routine\n");
      bus_kill();
  }
  else if (choice == 2) {
    printf("\n\nRunning terminal kill trap routine\n");
    term_kill();
  }
  else if (choice == 3) {
    printf("\n\nRunning kill(1) trap routine\n");
    kill_one();
  }
  else if (choice == 4) {
    printf("\n\nRunning kill(2) trap routine\n");
    kill_two();
  }
  else if (choice == 5) {
    printf("\n\nRunning software exception trap routine\n");
    soft_sig();
  }
  
}

/*********************************************************************/
/* Handle the signals for the above routines and print appropriate   */
/* message, then return to previous routine                          */
/*********************************************************************/

void sig_handle(int signo){
    
    if (signo==SIGBUS){
	printf("Just received a bus error\n");
    }
    else if (signo==SIGINT){
	printf("Just received a CTRL C sequence\n");
    }
    else if (signo==SIGHUP){
	printf("Child received a HUP signal\n");
    }
    else if (signo==SIGUSR1){
	printf("Child received user defined signal #1\n");
    }
    else if (signo==SIGCHLD){
	printf("Child just terminated\n");
    }
}