Sunday, October 19, 2014

Unix Prog: system function and signals

1. Signals from system

system.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<signal.h>  
 #include<unistd.h>  
   
 void sig_int(int signo)  
 {  
  printf("caught SIGINT\n");  
 }  
   
 void sig_chld(int signo)  
 {  
  printf("caught SIGCHLD\n");  
 }  
   
 int main(int argc, char* argv[])  
 {  
  if(signal(SIGINT, sig_int) == SIG_ERR) {  
   printf("signal error!\n");  
   exit(1);  
  }  
   
  if(signal(SIGCHLD, sig_chld) == SIG_ERR) {  
   printf("signal error!\n");  
   exit(1);  
  }  
   
  if(system("date") < 0) {  
   printf("system() error!\n");  
   exit(2);  
  }  
   
  exit(0);  
 }  

shell:
After system exits, child process sent the SIGCHLD back to parent process.
This is how system is implemented at current system. But actually system should block SIGCHLD at best.
 ubuntu@ip-172-31-23-227:~$ ./system.out  
 Sun Oct 19 15:53:33 UTC 2014  
 caught SIGCHLD  

2. system implementation
system.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<signal.h>  
 #include<sys/wait.h>  
 #include<errno.h>  
   
 int my_system(const char* cmdstring)  
 {  
  pid_t pid;  
  int status;  
  struct sigaction ignore, saveintr, savequit;  
  sigset_t chldmask, savemask;  
   
  if(cmdstring == NULL) return 1;  
   
  // Setup sigaction for SIGINT, and SIGQUIT to be SIG_IGN  
  ignore.sa_handler = SIG_IGN;  
  sigemptyset(&ignore.sa_mask);  
  ignore.sa_flags = 0;  
  if(sigaction(SIGINT, &ignore, &saveintr) < 0)  
   return -1;  
  if(sigaction(SIGQUIT, &ignore, &savequit) < 0)  
   return -1;  
   
  // Block the SIGCHLD signal  
  sigemptyset(&chldmask);  
  sigaddset(&chldmask, SIGCHLD);  
  if(sigprocmask(SIG_BLOCK, &chldmask, &savemask) < 0)  
   return -1;  
   
  // Launch the child process  
  if((pid = fork()) < 0) {  
   status = -1;  
  } else if (pid == 0) {  
   // In child process, restore the SIGINT, SIGQUIT handler  
   // restore the signal mask. So child process can accept all signals  
   sigaction(SIGINT, &saveintr, NULL);  
   sigaction(SIGQUIT, &savequit, NULL);  
   sigprocmask(SIG_SETMASK, &savemask, NULL);  
   
   execl("/bin/sh", "sh", "-c", cmdstring, (char*) 0);  
   _exit(127);  
  } else {  
   // In parent process, wait for the child process complete  
   while(waitpid(pid, &status, 0) < 0) {  
    if(errno != EINTR) {  
     status = -1;  
     break;  
    }  
   }  
  }  
   
  // Restore the SIGINT, SIGQUIT action, and restore the signal mask  
  if(sigaction(SIGINT, &saveintr, NULL) < 0)  
   return -1;  
  if(sigaction(SIGQUIT, &savequit, NULL) < 0)  
   return -1;  
  if(sigprocmask(SIG_SETMASK, &savemask, NULL) < 0)  
   return -1;  
   
  return status;  
 }  
   
 int main(int argc, char* argv[])  
 {  
  my_system("date");  
  exit(0);  
 }  

shell:
 ubuntu@ip-172-31-23-227:~$ ./system.out  
 Sun Oct 19 18:19:50 UTC 2014  

No comments:

Post a Comment