Interrupted system call in C - c

I want to make my program sleep upto 10 seconds even the signal is occured. So, I tried the following program.
Program:
#include<stdio.h>
#include<signal.h>
#include<errno.h>
int main()
{
printf("PID: %d\n",getpid());
int unslept=10;
while(unslept>0){
unslept=sleep(unslept);
if(errno==EINTR)
continue;
}
return 0;
}
Output:
$ ./a.out
PID: 18935
User defined signal 1
$
I expect the above program will execute 10 seconds even the signal is interrupted. I exeperiment it like, in one terminal I
executed this program. And using another terminal using kill command I sent the SIGUSR1 signal to this process. But, the same problem
occurs. Once the signal is passed, the program terminates. So, is there any way to execute my program upto 10 seconds without affecting
any signal.

You can ignore the signal. See the below example, in that example, if the SIGUSR1 signal is interrupted, it just ignore the signal using the SIG_IGN.
#include<stdio.h>
#include<signal.h>
int main(void)
{
if (signal(SIGUSR1, SIG_IGN) == SIG_ERR)
perror("SIGUSR1");
sleep(30);
}

You can use signal handling mechanism. Register your method that will handle interrupt signals and just ignore it that in your function.
// signal handler
void my_function(int sig){
//do nothing
}
// register signal
signal(SIGNAL_ID, my_function);

Related

When do we need to establish signal function again inside a signal handler?

I've got a simple program under linux and it works well:
#include<unistd.h>
#include<stdio.h>
#include<signal.h>
#include<sys/types.h>
void fStop(int signo){
printf("Hup\n");
}
int main(){
signal(SIGHUP,fStop);
for(;;){
pause();
}
return 0;
}
It runs and waits for signals. Each time I send "kill -1 xxx" to it, it prints a "Hup" line. OK
But my questions are:
I found if I remove the "for" loop, seems the pause() won't work after receiving SIGHUP signal. Does it mean that signal will interupt any kind of sleep and suspension functions?
In some linux programs, I see people re-estbalish signal function inside a signal handler like:
void fStop((int signo){
printf("Hup\n");
signal(SIGHUP,fStop);//When is this necessary?
}
Just a bit confused how linux signal handler should be designed, when to re-establish handler, depends on different signals?
Thanks.
Does it mean that signal will inter[r]upt any kind of sleep and suspension functions?
Probably not all, but it interrupts pause(), yes.
From pause()'s documentation (Linux):
RETURN VALUE
pause() returns only when a signal was caught and the signal-catching
function returned. In this case, pause() returns -1, and errno is
set to EINTR.

In C, linux, about kill signal and sleep() in loop

I run my C program on Mac OS. Part of my program is as following. This code runs well on sigint signal but can't work on sigkill signal.
void sigkill(int sig){
/*some code neglected*/
exit(0);
}
void sigint(int sig){
flag=1;
}
void alive(void) {
signal(SIGINT, sigint);
signal(SIGKILL, sigkill);
alarm(10);
while(1){
//printf("%d\n",flag);
sleep(1);
if(flag==1){
printf("no\n");
flag=0;
}
}
}
I have four questions:
At first I didn't write sleep(1), It can enter the function sigint(), and change the flag value, I can see from the printf. However, no "no" output as I expected.
After I added sleep function, it works well. I suppose the while loop would check flag every 1 second, and output "no" if flag=1. However, it seems the "no" output everytime when I press ctrl+c. Why it don't wait for one second?
The question said "You should not use 'sleep()' to wait 10 seconds. Use alarm(), coupled with a loop." I want to know how to implement this without sleep().
The kill command can't invoke sigkill function, how to fix this?
In general, signals can only be "caught" by your application when it makes a system call into the kernel. If you do a plain while(1) { if (flag==1){...} }, that will never call into the kernel. Theoretically, when you do your outer printf in the while(1) loop, that should call into the kernel and so the signal could be caught.
sleep() is interrupted by any signal. Check the man page for sleep(3).
check the man page for alarm(2).
You cannot change the signal handler for SIGKILL nor for SIGSTOP. These signal effects are hardcoded into the kernel. From sigaction(2):
signum specifies the signal and can be any valid signal except SIGKILL and SIGSTOP.
The kill command with no arguments does not generate a SIGKILL signal; it generates SIGTERM.

Can't catch signals after exec

I trying to make program reload itself after it receives signal. I have this code
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void signal_callback_handler(int signum){
printf("Caught signal %d\n",signum);
execv("./test", NULL); //reexec myself
}
int main()
{
signal(SIGINT, signal_callback_handler);
printf("Program STARTED\n");
while(1){
printf("Program processing stuff here.\n");
sleep(1);
}
return EXIT_SUCCESS;
}
The problem is that after exec program just ignore signal instead of calling signal handler.
Output:
Program STARTED
Program processing stuff here.
Program processing stuff here.
^CCaught signal 2
Program STARTED
Program processing stuff here.
^C^CProgram processing stuff here.
^C^C^C^C^CProgram processing stuff here.
^C^CProgram processing stuff here.
How to make signal handlers work after exec?
Signal masks are inherited across exec, and SIGINT is blocked during the invocation of your signal handler, which calls execve. Thus your re-exec'd image is started with SIGINT blocked.
If you strace the process, you'll see that your signal call becomes something like:
3143 rt_sigaction(SIGINT, {0xabcd, [INT], SA_RESTORER|SA_RESTART, 0xabcd}, {SIG_DFL, [], 0}, 8) = 0
^^^^^
|
+--- SIGINT is blocked during handler!
sigaction will give you finer control over the signal handler, and is recommended over signal.
Yor signal is blocked during execution of the signal handler, and the signal mask is inherited over exec. You need to reset it explicitly.
A potential problem here is that if you unblock inside the handler, and you have another signal pending, it will be delivered immediately, causing the handler to be executed again. This should be rare but it can happen.
Worse yet, if you unblock in the re-exec'd process and you have a signal pending, you may have it delivered to the re-exec'd process, potentially killing it. So set up a handler in the "child" first, then unblock.

Why SIGINT is send to a child process and does nothing?

I am building a simple debugger for my university class and I have a problem in handling SIGINT.
What I want to do is when the debugger process (from now on PDB) takes a SIGINT signal passes that to the child process (the one that is being actually debugged by PDB).
I am doing this:
pid_t childid;
void catch_sigint(int sig)
{
signal(SIGINT,SIG_DFL);
kill(childid,sig);
}
int debuger (char *address, parm *vars)
{
int ignore=1;
int status;
childid = fork();
signal(SIGINT,catch_sigint);
if(childid==0)
{
ptrace(PTRACE_TRACEME,0, NULL,NULL);
if(execve(address,NULL,NULL)==-1)
{
perror("ERROR occured when trying to create program to trace\n");
exit(1);
}
}
else
{
int f_time=1;
while(1)
{
long system_call;
wait(&status);
if(WIFEXITED(status))break;
if(WIFSIGNALED(status))break;
system_call = ptrace(PTRACE_PEEKUSER,childid, 4 * ORIG_EAX, NULL);
if(!strcmp(vars->category,"process-control") || !strcmp(vars->category,"all"))
ignore = pr_calls(system_call,ignore,limit,childid,vars->mode); //function that takes the system call that is made and prints info about it
if(!strcmp(vars->category,"file-management") || !strcmp(vars->category,"all"))
ignore = fl_calls(system_call,ignore,limit,childid,vars->mode);
if(f_time){ignore=1;f_time=0;}
ptrace(PTRACE_SYSCALL,childid, NULL, NULL);
}
}
signal(SIGINT,SIG_DFL);
return 0;
}
This program runs and forks a child process and execs a program to trace its system calls. That works fine when it doesn't get any signal.
But when in the middle of some tracing I press ctrl+c I expect the child process to stop and PDB to continue and stop (because of this line if(WIFSIGNALED(status))break;. That never happens. The program it traces continues its system calls and prints.
The tracing program is that:
#include <stdio.h>
int main(void)
{
for(;;) printf("HELLO WORLD\n");
return 0;
}
That program continues printing HELLO WORLD even after I hit ctrl+c.
I also observed that the system calls that ptrace gives after ctrl+c are -38 and that the status in wait changes only once after the signal from 1407 (I think is the normal value) to 639 and then back again to 1407 on the next wait.
So what I am doing wrong in that?
The problem it's on this line:
ptrace(PTRACE_SYSCALL,childid, NULL, NULL);
It has to be like that:
ptrace(PTRACE_SYSCALL,childid, NULL, signal_variable);
Where signal_variable is an int declared in global scope so the handler and the debugger can see it. It has a starting value of 0.
The signal handler now takes the signal and passes it in this variable and at the next loop when the ptrace orders the tracee program to continue it sends it the signal too.
That happens because when you trace a program the tracee stops execution when it receives a signal and waits further instruction for what to do with the signal from the tracer through ptrace.

-SIGCONT does not continue paused process?

The following process does not continue after running kill -SIGCONT pid from another terminal.
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("paused\n");
pause();
printf("continue\n");
return 0;
}
I expect the program to continue after sending the signal and printing "continue". How come this doesn't work as expected?
pause() is documented to
cause the calling process (or thread) to sleep until a signal is delivered that either terminates the process or causes
the invocation of a signal-catching function.
But SIGCONT only continues a process previously stopped by SIGSTOP or SIGTSTP.
So, you might want to try:
kill(getpid(), SIGSTOP);
Instead of your pause()
Also, you might want to look at sigsuspend().

Categories

Resources