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