sigset: ignoring ctrl-c in Unix - c

I am trying to make my program ignore Ctrl+C in unix which seems to work, the issue is that it keep writing "Syntax error". Here is the code
extern "C" void ignore( int sig )
{
fprintf( stderr, "\n"); // Print a new line
// This function does nothing except ignore ctrl-c
}
int main()
{
// For ctrl-c
sigset( SIGINT, ignore );
while (1) {
getUserInput();
}
return 0;
}
Everytime I hit Ctrl+C it runs through getUserInput again, which is the expected behavior, but it writes "Syntax error" as well. I checked and the "ignore" function gets executed, and once it has been executed, then it prints the error message, I am not sure why.
Does anyone have any clues please?
Thank you very much,
Jary

Do not use sigset(). Although it is in POSIX 2008, it is marked obsolescent - and also unsafe in threaded programs.
You then have a choice between signal(), which is blessed by ISO C but has some undesirable characteristics, and sigaction() which is the preferred solution in POSIX systems.
One key point with signal handling is to ensure you do not trap any signals that are ignored when you enter the program - unless you know something that the caller can't (such as you need to trap SIGCHLD signals for dead children).
This leads to the standard formulations, preached since time immemorial, for signal():
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, ignore);
Or, for sigaction():
struct sigaction new_sa;
struct sigaction old_sa;
sigfillset(&new_sa.sa_mask);
new_sa.sa_handler = SIG_IGN;
new_sa.sa_flags = 0;
if (sigaction(SIGINT, &new_sa, &old_sa) == 0 && old_sa.sa_handler != SIG_IGN)
{
new_sa.sa_handler = ignore;
sigaction(SIGINT, &new_sa, 0);
}
Since you do not show us the getUserInput() function, there is no way we can prognosticate on why you see 'Syntax Error'. However, if you have a grammar at work, it may well be that your read is not returning valid data, and the parser is unhappy with what is left in the buffer for it to process.

(Note: for more portability, you should probably use signal() (C standard library) or sigaction() (POSIX) instead of sigset(), but I don't think that's the problem here.)
You're not really ignoring the signal here; you're catching it and taking your own action - but it's likely that a system call has returned an error as a result of the interruption.
e.g. maybe you've caused a read system call to fail with EINTR. I suspect the real problem is that some code inside getUserInput() is not handling this error case.
You can ignore the signal completely by setting the handler to the special value SIG_IGN, which should work with any of sigset(), signal() or sigaction().

The "Syntax Error" message must be coming from the getUserInput function (or something it calls, of course) -- you could investigate by having that function print out what it is receiving and why it is complaining.
Note that the canonical way to ignore a signal is to use the pre-defined SIG_IGN as the signal handler. e.g.
sigset(SIGINT, SIG_IGN)

ignore() does a lot more than nothing.
When you run this code on UNIX, SIGINT is delivered asynchronously on the same thread that is executing getUserInput(). If a SIGINT arrives while getUserInput() is accessing stderr, the behavior is undefined because fprintf() usually isn't designed to be reentrant. (However, the behavior is likely to include garbled and/or repeated output. Did your program print "Syntax Error" before the SIGINT was delivered?) CERT and GNU libc have some more info about this.
If you were running this code on Win32, SIGINT would be delivered asynchronously in a separate thread.

Related

When is it preferable to cause a segfault in a watchdog thread versus exiting normally to stop a process?

I am wondering if there is ever a good reason to exit a watchdog thread in the manner depicted, versus exiting with exit(). In the code I came across that brought this question to mind, a segfault was caused by de-referencing a null pointer with the strange line *(char **)0 = "watchdog timeout";.
Unless I'm mistaken, a thread calling exit() terminates the entire process. I interpret a segfault as an error, and not intended behavior, but perhaps there are times when it is desired.
void *watchdog_loop(void *arg) {
time_t now;
while(foo) {
sleep(1);
now = current_time();
if (watchdog_timeout && now - bar > watchdog_timeout) {
raise(SIGSEGV); //something went wrong
}
}
return NULL;
}
Is there ever a time that it would be more desirable to have a watchdog loop segfault intentionally, versus exiting nonzero?
It is never desirable to elicit undefined behavior, which is what the example code does. In particular, note well that that code is not required to cause a segfault to be delivered to the process, though it might reliably do so on certain systems.
However, one might indeed prefer to kill a process via a signal instead of by calling exit(), so as to achieve termination without executing any application or library cleanup code. This is a plausible goal for a watchdog. Even in that event, however,
Either the raise() or the abort() function would definedly cause a signal to be delivered to the process.
SIGSEGV seems an odd choice of signal. Any of SIGABRT, SIGTERM, or SIGKILL would make more sense to me. Of those,
SIGKILL is not specified by the C language spec, but rather by POSIX (and maybe others). On a POSIX system, SIGKILL cannot be blocked or caught, so it is a very good candidate for a signal to terminate the process as quickly and surely as possible.
SIGABRT is used by the abort() function, which also goes to some pains to try to overcome program resistance to being terminated that way. This is the most natural standard function to use to trigger an intentional abnormal program termination.
SIGTERM can be caught and / or blocked, but unlike SIGKILL, it is defined by the C language specification, and therefore is more portable. But I don't really see any advantage over SIGABRT, unless you intend to allow it to be handled.
Another alternative would be _exit() (POSIX) or _Exit() (C99 or later). These perform a cleaner shutdown than you can expect from termination via a signal, but without executing most cleanup code. Open files will be closed, and the parent process will observe the process to terminate normally with a failure status instead of terminating by being killed by a signal.

SigHandler causing program to not terminate

Currently I am trying to create a signal handler that, when it receives a SIGTERM signal, it closes open network sockets and file descriptors.
Here is my SigHandler function
static void SigHandler(int signo){
if(signo == SIGTERM){
log_trace("SIGTERM received - handling signal");
CloseSockets();
log_trace("SIGTERM received - All sockets closed");
if (closeFile() == -1)
log_trace("SIGTERM received - No File associated with XXX open - continuing with shutdown");
else
log_trace("SIGTERM received - Closed File Descriptor for XXX - continuing with shutdown");
log_trace("Gracefully shutting down XXX Service");
} else {
log_trace("%d received - incompatible signal");
return;
}
exit(0);
}
This code below sits in main
if (sigemptyset(&set) == SIGEMPTYSET_ERROR){
log_error("Signal handling initialization failed");
}
else {
if(sigaddset(&set, SIGTERM) == SIGADDSET_ERROR) {
log_error("Signal SIGTERM not valid");
}
action.sa_flags = 0;
action.sa_mask = set;
action.sa_handler = &SigHandler;
if (sigaction(SIGTERM, &action, NULL) == SIGACTION_ERROR) {
log_error("SIGTERM handler initialization error");
}
}
When I send kill -15 PID, nothing happens. The process doesn't terminate, nor does it become a zombie process (not that it should anyway). I do see the traces printing within the SigHandler function however, so I know it is reaching that point in the code. It just seems that when it comes to exit(0), that doesn't work.
When I send SIGKILL (kill -9 PID) it kills the process just fine.
Apologies if this is vague, I'm still quite new to C and UNIX etc so I'm quite unfamiliar with most of how this works at a low level.
Your signal handler routine is conceptually wrong (it does not use just async-signal-safe functions). Read carefully signal(7) and signal-safety(7) to understand why. And your handler could apparently work most of the time but still be undefined behavior.
The usual trick is to set (in your signal handler) some volatile sig_atomic_t variable and test that variable outside of the signal handler.
Another possible trick is the pipe(7) to self trick (the Qt documentation explains it well), with your signal handler just doing a write(2) (which is async-signal-safe) to some global file descriptor obtained by e.g. pipe(2) (or perhaps the Linux specific eventfd(2)...) at program initialization before installing that signal handler.
A Linux specific way is to use signalfd(2) for SIGTERM and handle that in your own event loop (based upon poll(2)). That trick is conceptually a variant of the pipe to self one. But signalfd has some shortcomings, that a web search will find you easily.
Signals are conceptually hard to use (some view them as a design mistake in Unix), especially in multi-threaded programs.
You might want to read the old ALP book. It has some good explanations related to your issue.
PS. If your system is QNX you should read its documentation.
You should be using _exit from the signal handler instead, this also closes all the files.
Also read (very carefully) Basile's answer and take a long hard look at the list of async safe functions which you are allowed to use in signal handlers.
His advice about just changing a flag and testing it in your code is the best way if you need to do something you aren't allowed in the signal handler. Note that all blocking posix calls can be interrupted by signals so testing your atomic variable if you get an error on a blocking call (to say read) is a sure way to know if you have received a signal.

C: is signal() process-level?

I'm writing a tiny web server in C, and I want to ignore SIGPIPE signal so that my server won't terminate by trying to write to closed connection.
Signal(SIGPIPE, SIG_IGN);
I create thread to handle each request, and I set the signal ignore at main thread. But I think signal is process-level, so I believe this should work for any child thread created.(i.e, I don't have to call this signal ignore again in my child thread.) But still, my server will terminated for some reason. I still debugging on that, but I just want to make sure that it's not the SIGPIPE problem.....
Technically, the C standard says that using the signal function in a multithreaded environment results in undefined behavior (which is crazy, IMHO, especially if your calling it with SIG_IGN).
Practically, signal dispositions are process-wide, and it is recommended that new POSIX programs use sigaction instead of signal, as sigaction has better defined semantic (not that it matters for SIG_IGN).
In C99 and newer, you could call sigaction like so:
sigaction(SIGPIPE, &(struct sigaction){ .sa_handler = SIG_IGN }, 0);
(Note that if you call it correctly, you shouldn't have to check the return status since the only possible errors a, which arere EINVAL and EFAULT, which you'll only get if you provide ill-formed arguments.)

Handle signals in ncurses

I am writing a program in C using ncurses.I am trying to handle the CRTL C signal. In my code, this signal is being caught and dealt with but the program is not termination correctly. Could it be the way I am exiting from ncurses?
//handle SIGINT signal
void handle_signal(int signal){
if(signal == SIGINT){
clear();
mvprintw(3,3,"A SIGNAL WAS ENCOUNTERED");
refresh();
sleep(1/2);
exit(0);
} //close if statement
}//close handle_signal() function
Without further research: I'd be VERY surprised if curses functions were actually signal safe. It's generally best practice to keep your signal handlers minmal, ideally just setting a flag. So, you should solve your problem like this:
static volatile sig_atomic_t interrupted = 0;
in your signal handler:
if (signal == SIGINT)
{
interrupted = 1;
}
somewhere in your main loop:
if (interrupted)
{
clear();
mvprintw(3,3,"A SIGNAL WAS ENCOUNTERED");
refresh();
sleep(1);
endwin();
exit(0);
}
Note your code didn't call endwin() anywhere, this is required for restoring the terminal to normal.
As noted in the initscr manual page, ncurses installs a handler for SIGINT
The handler attempts to cleanup the screen on exit. Although it
usually works as expected, there are limitations:
If you setup your handler before initscr (or newterm), it will not be called. If you setup the handler after, you'd have to take into account the various limitations of what functions you can safely call in a signal handler.
ncurses' handling of SIGINT takes into account the fact that some of the functions it would normally use are not safe, and it uses a different strategy when it has receive a signal (which is perhaps not 100% reliable, but an improvement).
Your signal handler does not take any of that into account, and for example ncurses could call malloc to handle some extra output-buffering needed, and "not work", since malloc is not a safe function to use.
Further reading:
Apparent malloc from signal handler (and followup)
I need a list of Async-Signal-Safe Functions from glibc
signal - overview of signals

Send behavior on Broken pipe

While writing a simple server-client application, this question came in my mind. When someone tries to write to a broken pipe, a SIGPIPE would be generated. Let's say I handle the signal in my code.
Now what error does the write call returns - EPIPE or EINTR ( as it was interrupted by a signal). I tried with a sample program and I seem to be getting EPIPE always. Is this a guaranteed behavior or it could be any of the two error values?
POSIX says that EPIPE should be returned and SIGPIPE sent:
For write()s or pwrite()s to pipes or FIFOs not open for reading by any process, or with only one end open.
For write()s to sockets that are no longer connected or shut down for writing.
You can have a look at the POSIX standard here
The write(2) call returns -1 on error, so I guess you are asking about the value of errno(3).
You'll get EPIPE if you handle, block, or ignore the signal. Otherwise the process is terminated by default, see signal(7).
In general, "interrupted by a signal" (EINTR) refers to the utterly ridiculous Unix System V signal handling, whereby ANY system call could fail if your process received (and handled) a signal during the system call. This required wrapping every system call with do ... while (ret==-1 && errno==EINTR); or similar. While POSIX still allows either this or the good ("BSD") behavior, sane systems like GNU/Linux have the BSD behavior by default. You can always obtain the BSD behavior by calling sigaction with the right arguments, or even make a wrapper function to do so for you.
As such, EINTR is unrelated to the SIGPIPE caused by write errors.

Resources