Some time ago I found this exercise in C: without changing the main function, so that receiving a SIGUSR1 signal output is directed and added to a file in append mode as the first parameter. At the reception of another SIGUSR1 the output is directed to the console, and so on. How do such an exercise?
#include <stdio.h>
#include <time.h>
void redirectsetup (char *s){
}
int main (int argc, char *argv[]){
redirect setup(argv[1]);
while(1){
time_t now = time(NULL);
printf("%s",ctime(&now));
sleep(1);
}
}
I'll give you some general pointers.
You need to install a signal handler. Try typing man signal or googling "signal handler linux". As a rule your signal handler should do the minimum possible, many things are illegal in signal handlers including much of the C library. In this case, you could have it set a variable which tells you where to direct output and leave it at that.
Your main program needs to loop, sending characters to wherever the variable tells it.
One thing you might need to be careful of is a signal interrupting a system call, requiring it to be retried.
Have a go and see if you can make it work.
Related
I am trying to learn Signals. I know invalid memory access will cause segfault. So, I register a signal handler for SIGSEGV signal.
#include <stdio.h>
#include <signal.h>
void sighandler(int signum)
{
printf("%s\n", __func__);
}
int main()
{
int *a = NULL;
signal(SIGSEGV, sighandler);
*a = 5;
return 0;
}
Running this code, I am continuously getting SIGSEGV Signals. I thought i should only get the signal once. Can you guys explain why I am getting signals continuously
After the SEGV handler finishes, the instruction that triggered re-executes. Since you didn't do anything to prevent the next execution from faulting, you get SEGV again, ad infinitum.
See more in this answer.
The signal handler is returning to instruction that triggered it namely *a = 5 which is causing it to loop.
You have several problems including the use of printf inside a signal handler.
There are safe and not-safe ways of dealing with this
NOTES
Using signal(2) is not recommended for signal handling in general.
Handling SIGSEGV is even more complicated because of the way the signal semantics work. Quoting from the man page:
The only portable use of signal() is to set a signal's disposition to SIG_DFL or SIG_IGN. The semantics when using signal()
to establish a signal handler vary across
systems (and POSIX.1 explicitly permits this variation); do not use it for this purpose.
POSIX.1 solved the portability mess by specifying sigaction(2), which provides explicit control of the semantics when a
signal handler is invoked; use that interface instead of signal().
So the first thing you should do is use sigaction.
Next, handling SIGSEGV is a weird beast:
How to write a signal handler to catch SIGSEGV?
and
Does linux allow any system call to be made from signal handlers?
have good answers and get into specific details. There are external links in some of the answers given there.
How to do this using signal(2)
Well :-) let's say you want to use signal(2) and you want to play with this in a weird way....
You can use sigjmpset and siglongjmp.
sigjmpset marks a point where siglongjmp should jump to. The first time sigjmpset is called (to set the point) it returns 0. When siglongjmp jumps to it, (which means it gets called again as a result of the long jump), it returns 1.
Which means we can do this:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <setjmp.h>
sigjmp_buf env;
int sigsav;
void sighandler(int signum)
{
const char msg[] = "Skipping signal\n";
write(2, msg, sizeof(msg));
siglongjmp(env, sigsav);
}
int main()
{
int *a = NULL;
signal(SIGSEGV, sighandler);
if(!sigsetjmp(env, sigsav)) {
printf("setting value of a\n");
*a = 5;
}
else {
printf("returned to sigsetjmp, but now we skip it!\n");
}
return 0;
}
I am a newbie in Linux programming.I copied the code below from a book:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void ouch (int sig)
{
printf("OUCH! - I got signal %d\n", sig);
(void) signal(SIGINT, SIG_DFL);
}
int main ()
{
(void) signal(SIGINT, ouch);
while(1)
{
printf("Hello World!\n");
sleep(1);
}
}
It was expected to print something when Ctrl+C was entered.But it do nothing but print Hello World!.
EDIT:
I am so sorry that I have binded the Ctrl+C as a short-cut key for copy.
Sorry for trouble caused.
My Suggestion is don't use printf in siginal handler (ouch), it may be undefined behavior. Async-signal-safe functions: The list of safe functions that can be call in signal handler man page.
It is not safe to call all functions, such as printf, from within a signal handler.
A useful technique is to use a signal handler to set a flag and then check that flag
from the main program and print a message if required.
Reference: Beginning Linux Programming, 4th Edition,In this book exactly your code is explained, Chapter 11: Processes and Signals, page 484
An additional helpful link:
Explanation: Use reentrant functions for safer signal handling
Sorry, I can't see a question here... but I can guess what you are interested in.
printf() is a stateful function, thus not reentrant. It uses a FILE structure (variable name is 'stdin') to keep it's state. (It is like calling fprintf(stdin,format,...)).
That means, dependant on implementation and 'luck', calling printf() from a signal handler may print what you expect, but also may print nothing or may even crash or worse, smash your memory! Anything could happen.
So, just don't call functions from within a signal handler that are not explicitely marked 'signal-safe'. You will avoid lot's of headaches in the long term.
Put an fflush(stdout) in your signal handler. It was just buffered, then the second SIGINT exited the program before the buffer could be flushed.
I read about add signal() function in the signal handler function can over write the default behaviour:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void signalHandler();
int main(void) {
signal(SIGUSR1, signalHandler);
sleep(60);
printf("I wake up");
return 0;
}
void signalHandler() {
signal(SIGUSR1, signalHandler);// I add this line to overwrite the default behaviour
printf("I received the signal");
}
And I trigger it with another process
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
kill(5061, SIGUSR1); // 5061 is the receiver pid, kill(argv[1], SIGUSR1) doesn't working, when I get 5061 as parameter
puts("send the signal ");
return 0;
}
The receiver process wake up as soon as it receiver the SIGUSR1 signal. How can I make the receiver continue sleep even when it receive the signal from other process?
BTW why kill(5061, SIGUSR1); 5061 is the receiver pid, kill(argv[1], SIGUSR1) doesn't work, when I get 5061 as parameter?
From the sleep(3) manual page:
Return Value
Zero if the requested time has elapsed, or the number of seconds left to sleep, if the call was interrupted by a signal handler.
So instead of just calling sleep you have to check the return value and call in a loop:
int sleep_time = 60;
while ((sleep_time = sleep(sleep_time)) > 0)
;
Your question (why kill(argv[1], SIGUSR1) does not work) actually is not related to signals, but to basic C programming. Please compile with gcc -Wall -g (i.e. all warnings and debugging information) on Linux, and improve your code till no warning is given.
Please read carefully the kill(2) man page (on Linux, after installing packages like manpages and manpages-dev and man-db on Ubuntu or Debian, you can type man 2 kill to read it on your computer). Read also carefully signal(2) and signal(7) man pages. Read these man pages several times.
Then, understand that the kill syscall is declared as
int kill(pid_t pid, int sig);
and since pid_t is some integral type, you need to convert argv[1] (which is a string, i.e. a char*) to some integer (and kill(argv[1], SIGUSR1) should not even compile without errors, since argv[1] is not some integer but a string). So please use:
kill((pid_t) atoi(argv[1]), SIGUSR1);
The man page says also that you should use signal(SIGUSR1, SIG_DFL) to restore the default behavior, and signal(SIGUSR1, SIG_IGN) to ignore that signal.
Of course, you should better use sigaction(2) as the man page of signal(2) tells you.
At last, please take the habit of reading man pages and spend hours to read good books like Advanced Linux Programming and Advanced Unix Programming. They explain things much better than we can explain in a few minutes. If you are not familiar with C programming, read also some good book on it.
I haven't tried it before, but you could use sigaction(2) instead and set the SA_RESTART flag, this should make syscalls restartable.
Edit:
Actually this won't work, according to the man page of signal(7) not all system calls are restartable:
The sleep(3) function is also never restarted if interrupted by a
handler, but gives a success return: the number of seconds remaining
to sleep.
So you should call the sleep function again with the remaining time instead.
Here is my code,
#include<signal.h>
#include<stdio.h>
int main(int argc,char ** argv)
{
char *p=NULL;
signal(SIGSEGV,SIG_IGN); //Ignoring the Signal
printf("%d",*p);
printf("Stack Overflow"); //This has to be printed. Right?
return 0;
}
While executing the code, i'm getting segmentation fault. I ignored the signal using SIG_IGN. So I shouldn't get Segmentation fault. Right? Then, the printf() statement after printing '*p' value must executed too. Right?
Your code is ignoring SIGSEGV instead of catching it. Recall that the instruction that triggered the signal is restarted after handling the signal. In your case, handling the signal didn't change anything so the next time round the offending instruction is tried, it fails the same way.
If you intend to catch the signal change this
signal(SIGSEGV, SIG_IGN);
to this
signal(SIGSEGV, sighandler);
You should probably also use sigaction() instead of signal(). See relevant man pages.
In your case the offending instruction is the one which tries to dereference the NULL pointer.
printf("%d", *p);
What follows is entirely dependent on your platform.
You can use gdb to establish what particular assembly instruction triggers the signal. If your platform is anything like mine, you'll find the instruction is
movl (%rax), %esi
with rax register holding value 0, i.e. NULL. One (non-portable!) way to fix this in your signal handler is to use the third argument signal your handler gets, i.e. the user context. Here is an example:
#include <signal.h>
#include <stdio.h>
#define __USE_GNU
#include <ucontext.h>
int *p = NULL;
int n = 100;
void sighandler(int signo, siginfo_t *si, ucontext_t* context)
{
printf("Handler executed for signal %d\n", signo);
context->uc_mcontext.gregs[REG_RAX] = &n;
}
int main(int argc,char ** argv)
{
signal(SIGSEGV, sighandler);
printf("%d\n", *p); // ... movl (%rax), %esi ...
return 0;
}
This program displays:
Handler executed for signal 11
100
It first causes the handler to be executed by attempting to dereference a NULL address. Then the handler fixes the issue by setting rax to the address of variable n. Once the handler returns the system retries the offending instruction and this time succeeds. printf() receives 100 as its second argument.
I strongly recommend against using such non-portable solutions in your programs, though.
You can ignore the signal but you have to do something about it. I believe what you are doing in the code posted (ignoring SIGSEGV via SIG_IGN) won't work at all for reasons which will become obvious after reading the bold bullet.
When you do something that causes the kernel to send you a SIGSEGV:
If you don't have a signal handler, the kernel kills the process and that's that
If you do have a signal handler
Your handler gets called
The kernel restarts the offending operation
So if you don't do anything abut it, it will just loop continuously. If you do catch SIGSEGV and you don't exit, thereby interfering with the normal flow, you must:
fix things such that the offending operation doesn't restart or
fix the memory layout such that what was offending will be ok on the
next run
Another option is to bracket the risky operation with setjmp/longjmp, i.e.
#include <setjmp.h>
#include <signal.h>
static jmp_buf jbuf;
static void catch_segv()
{
longjmp(jbuf, 1);
}
int main()
{
int *p = NULL;
signal(SIGSEGV, catch_segv);
if (setjmp(jbuf) == 0) {
printf("%d\n", *p);
} else {
printf("Ouch! I crashed!\n");
}
return 0;
}
The setjmp/longjmp pattern here is similar to a try/catch block. It's very risky though, and won't save you if your risky function overruns the stack, or allocates resources but crashes before they're freed. Better to check your pointers and not indirect through bad ones.
Trying to ignore or handle a SIGSEGV is the wrong approach. A SIGSEGV triggered by your program always indicates a bug. Either in your code or code you delegate to. Once you have a bug triggered, anything could happen. There is no reasonable "clean-up" or fix action the signal handler can perform, because it can not know where the signal was triggered or what action to perform. The best you can do is to let the program fail fast, so a programmer will have a chance to debug it when it is still in the immediate failure state, rather than have it (probably) fail later when the cause of the failure has been obscured. And you can cause the program to fail fast by not trying to ignore or handle the signal.
The example code of section 10.6, the expected result is:
after several iterations, the static structure used by getpwnam will be corrupted, and the program will terminate with SIGSEGV signal.
But on my platform, Fedora 11, gcc (GCC) 4.4.0, the result is
[Langzi#Freedom apue]$ ./corrupt
in sig_alarm
I can see the output from sig_alarm only once, and the program seems hung up for some reason, but it does exist, and still running.
But when I try to use gdb to run the program, it seems OK, I will see the output from sig_alarm at regular intervals.
And from my manual, it said the signal handler will be set to SIG_DEF after the signal is handled, and system will not block the signal. So at the beginning of my signal handler I reset the signal handler.
Maybe I should use sigaction instead, but I only want to know the reason about the difference between normal running and gdb running.
Any advice and help will be appreciated.
following is my code:
#include "apue.h"
#include <pwd.h>
void sig_alarm(int signo);
int main()
{
struct passwd *pwdptr;
signal(SIGALRM, sig_alarm);
alarm(1);
for(;;) {
if ((pwdptr = getpwnam("Zhijin")) == NULL)
err_sys("getpwnam error");
if (strcmp("Zhijin", pwdptr->pw_name) != 0) {
printf("data corrupted, pw_name: %s\n", pwdptr->pw_name);
}
}
}
void sig_alarm(int signo)
{
signal(SIGALRM, sig_alarm);
struct passwd *rootptr;
printf("in sig_alarm\n");
if ((rootptr = getpwnam("root")) == NULL)
err_sys("getpwnam error");
alarm(1);
}
According to the standard, you're really not allowed to do much in a signal handler. All you are guaranteed to be able to do in the signal-handling function, without causing undefined behavior, is to call signal, and to assign a value to a volatile static object of the type sig_atomic_t.
The first few times I ran this program, on Ubuntu Linux, it looked like your call to alarm in the signal handler didn't work, so the loop in main just kept running after the first alarm. When I tried it later, the program ran the signal handler a few times, and then hung. All this is consistent with undefined behavior: the program fails, sometimes, and in various more or less interesting ways.
It is not uncommon for programs that have undefined behavior to work differently in the debugger. The debugger is a different environment, and your program and data could for example be laid out in memory in a different way, so errors can manifest themselves in a different way, or not at all.
I got the program to work by adding a variable:
volatile sig_atomic_t got_interrupt = 0;
And then I changed your signal handler to this very simple one:
void sig_alarm(int signo) {
got_interrupt = 1;
}
And then I inserted the actual work into the infinite loop in main:
if (got_interrupt) {
got_interrupt = 0;
signal(SIGALRM, sig_alarm);
struct passwd *rootptr;
printf("in sig_alarm\n");
if ((rootptr = getpwnam("root")) == NULL)
perror("getpwnam error");
alarm(1);
}
I think the "apue" you mention is the book "Advanced Programming in the UNIX Environment", which I don't have here, so I don't know if the purpose of this example is to show that you shouldn't mess around with things inside of a signal handler, or just that signals can cause problems by interrupting the normal work of the program.
According to the spec, the function getpwnam is not reentrant and is not guaranteed to be thread safe. Since you are accessing the structure in two different threads of control (signal handlers are effectively running in a different thread context), you are running into this issue. Whenever you have concurrent or parallel execution (as when using pthreads or when using a signal handler), you must be sure not to modify shared state (e.g. the structure owned by 'getpwnam'), and if you do, then appropriate locking/synchronization must be used.
Additionally, the signal function has been deprecated in favor of the sigaction function. In order to ensure portable behavior when registering signal handlers, you should always use the sigaction invocation.
Using the sigaction function, you can use the SA_RESETHAND flag to reset the default handler. You can also use the sigprocmask function to enable/disable the delivery of signals without modifying their handlers.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void sigalrm_handler(int);
int main()
{
signal(SIGALRM, sigalrm_handler);
alarm(3);
while(1)
{
}
return 0;
}
void sigalrm_handler(int sign)
{
printf("I am alive. Catch the sigalrm %d!\n",sign);
alarm(3);
}
For example, my code is runing in main doing nothing and every 3 seconds my program says im alive x)
I think that if you do as i done calling in the handler function alarm with value 3, the problem is resolved :)