Unable to handle signals on Linux from inside of forked process - c

I am trying to execute a fork function and use a signal handler in the child process, however when I run the program and try to send the signal the parent process gets the signal instead of the child process. The code:
pid_t id = fork();
if(id == 0)
{
struct sigaction ss;
ss.sa_handler = &sigstop;
sigaction(SIGTSTP, &ss, NULL);
int status;
status = execvp(arguments[0], arguments);
if(status == -1)
perror("MSH_ERROR (unknown command");
exit(EXIT_SUCCESS);
}
else
{
wait(NULL);
}

Related

is possible to get the exit status from the child of a child process in the parent

I try to get the exit code from a child of a child process in the parent process.
If the process goes in the while loop to fork again i don't get the exit code.
I tried some options for waitpid like WNOHANG but then the program hangs.
Maybe what i wan't is not possible because it's some like a zombie child?
This is my code.
void parrent_process(t_token *token, t_info *info)
{
pid_t pid;
int wstatus;
pid = fork();
if (pid == -1)
return (print_error_msg(FORK_FAIL, NULL, NULL));
if (pid == 0)
{
child_process(token);
}
if (info->in)
close(info->in);
waitpid(pid, &wstatus, 0);
if (WIFEXITED(wstatus))
info->exit_code = WEXITSTATUS(wstatus);
}
void child_process(t_token *token)
{
t_token *cmd_token;
pid_t pid;
pid = 0;
cmd_token = token;
while (token->next && ((token->next)->type == GREAT))
{
pid = fork();
if (pid == -1)
return (print_error_msg(FORK_FAIL, NULL, NULL));
if (pid == 0)
{
redirect_output(token);
break;
}
token = token->next->next;
}
if (execve(cmd_token->path, cmd_token->args, cmd_token->envp) == -1)
{
print_error_msg(CMD_NOT_FOUND, "minishell", cmd_token->args[0]);
exit(127);
}
}
In most POSIX-like systems, the answer is "No — a process can only wait on its own children, those it created directly with fork()1".
However, on Linux, there is the prctl(2) system call. The option PR_SET_CHILD_SUBREAPER allows a process to wait for more distant descendants (grandchildren, great-grandchildren, …) too. However, if the direct parent of a process waits for it, the ancestral process will not get the exit status information.
1 Or posix_spawn()

How to restart a child process from parent process in c

How to restart the child process from parent process when child process terminates. In one application I have created a child process which has an infinite while loop. The application runs in a router. When some event happens my child process terminates. But after rebooting the router everything works fine. Is it possible to restart my child process from parent process(parent process always works).
int main()
{
pid_t pid;
pid = fork();
if (pid == 0)
{
while(1)
{
printf("Child process\n");
sleep(1);
}
}
else
{
while(1)
{
printf("parrent process\n");
}
}
return 0;
}
Assuming you only start one process and it's another executable:
pid_t pid = 0;
void sigchld(int unused)
{
if (pid) {
int status = 0;
waitpid(pid, &status, WNOHANG);
if (WIFSTOPPED(status) || WIFCONTINUED(status)) return;
if (!WIFSIGNALED(status)) return; // It exited rather than terminated
pid = 0;
}
if ((pid = vfork() == 0) {
/* fork() isn't really signal safe anymore but vfork() still is! */
execle(...);
_exit(0);
}
}
int main()
{
pid = 0;
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigchld;
sa.sa_flags = SA_NODEFER;
sigaction(SIGCHLD, &sa, NULL);
kill(SIGCHLD, getpid());
while(1)
{
printf("parrent process\n");
}
}
Trivially adaptable to more than one, but if it's not another executable you have your work cut out from you. Attempting to fork() and run more code inside the signal handler is fraught with pearl. fork() itself is only safe if you haven't installed any pthread_atfork() handlers (which don't run in vfork()). You cannot call malloc() in a signal handler, and stdio is unreasonably tricky and best to assume it just doesn't work.

Inform parent process about child get signal after signal handler in child process is served

Hi currently I am collecting backtrace of child process in signal handler of child process . Then planning to send collected backtrace to parent process using message queue .
My problem is when child process get any signal. child signal handler runs but informs parent process that child exited normally instead of child get signal.
below is my code
void childProcess()
{
int h =0 ;
for(h=0;h<10;h++)
{
printf("child for loop running %d\n",h);
//sleep(1);
int q = 1/0; // generate floating point exception
}
exit(0);
}
void signalhandler(int signum, siginfo_t *si, void *arg)
{
printf("signal received %s\n",strsignal(signum));
printf("%d\n",signum);
void *array[100];
int size = 100;
int addrLen = backtrace(&array,size);
char ** sym = backtrace_symbols(&array,addrLen);
int j = 0;
printf("Test crashed due to %s\n",strsignal(signum));
for(j=0;j<addrLen;j++)
{
printf("%u : %s\n",array[j],sym[j]);
}
raise(signum);
exit(signum);
}
void registerSignals()
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = signalhandler;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGFPE, &sa, NULL);
}
int main()
{
//while(1)
{
pid_t pid;
pid = fork();
if(pid == 0)
{
// child
printf("child process id is %d\n",getpid());
registerSignals();
childProcess();
}
else
{
printf("parent process id is %d\n",getpid());
// parent
int iStatus;
pid_t childPID = waitpid(pid,&iStatus,0);
printf("iStatus is %d\n",WIFEXITED(iStatus));
if(childPID == -1)
{
printf("wait pid failed\n");
}
else if(WIFEXITED(iStatus)==1)
{
printf("child exited normally!\n");
}
else if (WIFSIGNALED(iStatus)==1)
{
printf("child process terminated abnormally !!\n");
int iSignalnumber = 0;
// to fetch the signal number
iSignalnumber = WTERMSIG(iStatus);
printf("child process terminated due to %s\n",strsignal(iSignalnumber));
// to check core file is generated or not
if(WCOREDUMP(iStatus)==1)
{
printf("core file is generated \n");
}
else
{
printf("core file is not generated \n");
}
}
int h ;
for(h = 0; h<10;h++)
{
printf("parent executing : %d\n",h);
}
}
printf("while loop executing with pid : %d \n", getpid());
sleep(1);
}
}
My requirement is after signal handler is served in child process the
parent should print "child process terminated abnormally !!" but I am
getting "child exited normally!" message
From wait()'s Linux docs:
WIFEXITED(wstatus)
returns true if the child terminated normally, that is, by
calling exit(3) or _exit(2), or by returning from main().
The child signal handler ends the process using exit(), so everything works a specified.
Remove the call to exit() from the signal handler to get the expected result.
The call to raise() inside the signal handler most likely leads to recursive calls, so remove is as well.

Signal handlers in mini shell project

This is what happens in my signal handler. Also signal_flag is a global variable.
volatile sig_atomic_t signal_flag = 0;
void sig_handler(int signo) {
if (signo == SIGTSTP) {
signal_flag = 1;
}
}
This the condition that occurs, provided my fork() works as its supposed to. I have the sleep set to 5 so I have enough time to press CTRL+Z after a command I'll give as an input and suspend the process.
pid_t child_pid = fork();
int status;
//GOT A SIGNAL.
if (signal(SIGTSTP, sig_handler) != SIG_ERR) {
signal(SIGTSTP, SIG_IGN);
kill(child_pid, SIG_IGN);
insert_suspended_process(child_pid, ACTIVE);
//_exit(EXIT_SUCCESS);
}
if (child_pid < 0) {
fprintf(stderr, "execute: fork failed.\n");
exit(EXIT_FAILURE);
}
if (child_pid == 0) {
/* child process. */
//print_child_messages();
char bin[512];
strcpy(bin, command[0]);
//strcat(bin, command[0]);
if (bars > 0) {
//Houston, we have pipes, I REPEAT, WE HAVE PIPES!
int pipefd[2], status;
pid_t cpid;
if (pipe(pipefd) == -1) {
fprintf(stderr, "execute: pipe failed.\n");
exit(EXIT_FAILURE);
}
cpid = fork();
pipe(pipefd);
}
sleep(3);
//executing...
execvp(bin, command);
_exit(EXIT_SUCCESS); //safer than exit().
}
else {
/* parent process. */
//print_parent_messages(child_pid);
//signal(SIGTSTP, SIG_IGN);
waitpid(child_pid, NULL, 0);
}
I'm making a shell as part of homework, and I'm requested to handle the SIGTSTP signal in a way that, when the user presses CTRL+Z my shell will suspend the ongoing process(i have set sleep(3) so I can suspend even a simple ls -al process)
My problem is that my code adds the process with that pid to my list via the insert_suspended_process(pid_t) function but this occurs without me pressing the CTRL+Z signal. Any thoughts or quidelines?
You don't seem to check the result of the fork() in the if (i==12). Also installing the signal handler AFTER the fork is a problem waiting to happen ..

Killing a child process from a signal handler

I'm writing a simple shell, and I have to fork a child process an external program using execv. I have to send the signal TSTP(Cntl+Z) to the signal handler, and then kill the currently running child process. My problem is I can't find a way to pass the Child pid into the signal handler. If i do a getpid() in the handler, it just returns the parent pid. I also tried setting the child pid as getpid() inside the child process, and having that variable as a global variable, but that also didn't work. Here is some of the code I have so far.
void handler(int);
//in main
if (!built_in_cmd(myArgc,myArgs)) {
pid_t pid;
char *x = myArgs[0];
if((pid=fork())<0)
printf("Parent: fork() process failed");
else {
if (pid == 0) {
y=getpid();
printf("Parent: My child has been spawned. %d %d\n",y,getppid());
execv(x, myArgs);
exit(0);
}
else {
signal(SIGTSTP,handler);
wait(0);
printf("Parent: My child has terminated.\n");
}
}
}
return;
//outside main
void handler(int signo){
kill(idk,SIGKILL);
}
Signals are asynchronous in nature, there's no way to pass any extra state to them except through global variables. Assuming that you only ever have one thread waiting for a child, it's safe to use a global, but otherwise there's no multithread-safe way of doing so:
// At global scope
pid_t child_pid = (pid_t)-1;
...
void myfunc()
{
pid_t pid;
if((pid = fork()) < 0)
...
else if(pid == 0)
...
else
{
child_pid = pid;
...
}
}

Resources