Implement Signal() using sigaction() in ubuntu - c

I am programming a client/server app where the client provides the file name, then the server sends it to client and finally the client will save it.
So I want to make signal handler to handle zombie problem between parent and child so this code for signal:
Sigfunc *
signal(int signo, Sigfunc *func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
#endif
} else {
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART; /* SVR4, 44BSD */
#endif
}
if (sigaction(signo, &act, &oact) < 0)
return(SIG_ERR);
return(oact.sa_handler);
}
/* end signal */
The filename is myHeader.h
and the error when compile the file is :
gcc -Wall -I/home/zmhnk/Desktop/ -o "myHeader" "myHeader.h" (in directory: /home/zmhnk/Desktop)
myHeader.h:281:1: error: unknown type name ‘Sigfunc’
myHeader.h:282:19: error: unknown type name ‘Sigfunc’
Compilation failed.
So how can this problem be solved?

You need to declare Sigfunc, so place something like this in your header file:
typedef void (*Sigfunc)(int sig_no);
in your header file.
And since there's already a standard function named signal , you need to name your function something else.

Related

Why is my signal handler not invoked more than once here?

jmp_buf functjmp;
void sigsegv_handler(int sig) {
sio_printf("Caught sigsegv!\n");
siglongjmp(functjmp, 2);
return;
}
void foo(unsigned val) {
assert(0);
sio_printf("entered!\n");
}
int main() {
struct sigaction action;
action.sa_handler = sigsegv_handler;
sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
sigaddset(&action.sa_mask, SIGSEGV);
action.sa_flags = SA_RESTART; /* Restart syscalls if possible */
if (sigaction(SIGSEGV, &action, NULL) < 0) {
sio_fprintf(stderr, "handler error!\n");
}
sigset_t prev_mask;
sigprocmask(SIG_BLOCK, NULL, &prev_mask);
if (sigsetjmp(functjmp, 0) == 0) {
foo(*(unsigned *)0x8);
} {
sigprocmask(SIG_BLOCK, &prev_mask, NULL);
sio_printf("jump handled!\n");
foo(*(unsigned *)0x8);
}
sio_fprintf(stderr, "how did it come here?!\n");
}
I've been debugging this code using gdb, and I cannot figure out why the program will not handle the second SIGSEGV signal with my own handler, assuming no other signals were received or sent by the program? Any sio prefixed functions are async safe variants of the stdio counterparts.
Currently, I surmise it has to do with something I'm missing in my conception about returning from the signal handler, which longjmp doesn't do at all.
Short answer: normally not possible to resume after SIGSEGV for C program. You might get more mileage with C++.
Long Answer: See discussions in Coming back to life after Segmentation Violation
Assuming OK to take the risk of undefined behavior:
It is possible to re-enable SEGV. The core issue is that during signal handler, the code explicitly blocks the SEGV signal from being triggered (with the sigaddset). In addition, the default behavior (of signal handlers) is that during signal handling, the same signal processing will be deferred until the signal handler returns. In the OP code, the signal handler never returns (because of the siglongjmp)
Both issues can be addressed by changing the original code.
// Make sure all attributes are NULL.
struct sigaction action = {} ;
action.sa_handler = sigsegv_handler;
sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
// Not Needed:: sigaddset(&action.sa_mask, SIGSEGV);
// Add SA_NODEFER to disable the deferred processing of SIGSEGV.
action.sa_flags = SA_RESTART | SA_NODEFER ; /* Restart syscalls if possible */
// rest of code here
if (sigaction(SIGSEGV, &action, NULL) < 0) {
sio_fprintf(stderr, "handler error!\n");
}
...

Change application core dump directory with c program

I have one scenario where I want to change directory for core dumps by current application using c program.
I have one option to do chdir() to specified directory. But this changes the home directory of application. And I am looking for some APIs which can change directory for core dumps only.
You can change core dump pattern globally through /proc/sys/kernel/core_pattern.
But if you only want to change the core dump directory of one process, you can do what Apache web server does - register a signal handler that changes the current directory right before core dumping:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/resource.h>
#define COREDUMP_DIR "/tmp"
static void sig_coredump (int sig)
{
struct sigaction sa;
// Change to the directory we want the core to be dumped
chdir (COREDUMP_DIR);
// Clear the signal handler for the signal
memset (&sa, 0, sizeof (sa));
sa.sa_handler = SIG_DFL;
sigemptyset (&sa.sa_mask);
sigaction (sig, &sa, NULL);
// Send the signal again
raise (sig);
}
int main (int argc, char **argv)
{
struct sigaction sa;
// Set up the signal handler for all signals that
// can cause the core dump
memset (&sa, 0, sizeof (sa));
sa.sa_handler = sig_coredump;
sigemptyset (&sa.sa_mask);
sigaction (SIGSEGV, &sa, NULL);
sigaction (SIGBUS, &sa, NULL);
sigaction (SIGABRT, &sa, NULL);
sigaction (SIGILL, &sa, NULL);
sigaction (SIGFPE, &sa, NULL);
// Enable core dump
struct rlimit core_limit;
core_limit.rlim_cur = RLIM_INFINITY;
core_limit.rlim_max = RLIM_INFINITY;
if (setrlimit (RLIMIT_CORE, &core_limit) == -1) {
perror ("setrlimit");
}
// Trigger core dump
raise (SIGSEGV);
return 0;
}
Note that as this relies on the crashing application itself setting up and being able to run the signal handler, it can't be 100% bullet-proof - signal may be delivered before signal handler is set up or signal handling itself may get corrupted.

SIGINT caught only one time

Given this code:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
void sigint_handler(int h)
{
printf("Hey! I caught a SIGINT! :)\n");
}
int main()
{
struct sigaction act;
act.sa_handler = &sigint_handler;
if (0 != sigaction(SIGINT, &act, NULL)) {
perror("unable to setup the SIGINT handler!\n");
return 1;
}
while(1) { }
return 0;
}
compiled with gcc 7.2.0 (kernel 4.13.12) using the following options: -Wall -pedantic -ansi -std=gnu11.
The first signal is always caught, but sometimes, the second one is not caught, and sometimes it is.
I encountered this bug while spamming Ctrl-C at process' startup.
What did I miss to catch all signals?
As Martin James observed in a comment:
Your SIGINT handler has only one line - a call to a function that is not async-signal safe:(
Somewhat later, I observed:
You've no idea what the other fields in the struct sigaction are set to because you didn't initialize act. Maybe you will get better behaviour if you set the documented fields to known values. You can use write() in a POSIX signal handler (not in standard C, but fortunately you're not using standard C). You shouldn't use printf(), though in this context it is unlikely to cause any trouble. One minor advantage of write() — there's no application level buffering to worry about.
The question How to avoid using printf() in a signal handler discusses which functions can be used in a signal handler. Note that the functions from the <string.h> header such as strlen() and strchr() are not listed amongst those that are async-signal safe. I find that omission puzzling, but that's what POSIX (2008 and earlier) says. (This was accurate for POSIX 2008. One of the changes in POSIX 2016 is that a number of signal-safe routines have been added to the list in Signal Concepts, including both strlen() and strchr() — this makes a lot of sense to me.)
I adapted your code like this:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static void sigint_handler(int h)
{
char message[] = "Hey! I caught a SIGINT x! :\n";
char *x = message;
while (*x != 'x' && *x != '\0')
x++;
if (*x != '\0')
*x = (h % 10) + '0';
write(1, message, sizeof(message) - 1);
}
int main(void)
{
struct sigaction act = { 0 };
act.sa_handler = &sigint_handler;
if (0 != sigaction(SIGINT, &act, NULL))
{
perror("Unable to setup the SIGINT handler!\n");
return 1;
}
while (1)
{
printf("Pausing for a moment...\n");
pause();
printf("You interrupted my dozing\n");
}
return 0;
}
The code uses pause() rather than spinning in a busy-loop. It's an unusual system call; it never returns normally (the exec*() family of functions never return normally either).
I compile with stringent warning options:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
> -Wstrict-prototypes sig13.c -o sig13
$
If I didn't use h (the argument to the signal handler), the code wouldn't compile, so I used it. The code avoids using string handling functions (char *x = strchr(message, 'x'); if (x != 0) *x = (h % 10) + '0'; would be clearer). The function is static because it won't be used outside this file — so there isn't a header to declare it.
When executed (on a Mac running macOS High Sierra 10.13.2, using GCC 7.2.0), it produces output like:
$ ./sig13
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^CHey! I caught a SIGINT 2! :
You interrupted my dozing
Pausing for a moment...
^\Quit: 3
$
The main moral to this is "make sure your variables are properly initialized". A secondary moral is to make sure your signal handler is clean.
I had two problems with my code, first of all, as mentionned by #MartinJames and #j31d0, the printf function is not async-signal-safe, so it can't be used inside the signal handler. It can be easily replaced by the write system-call which is async-signal-safe:
char message[255] = "Hey! I caught a SIGINT :)\n";
write(1, message, 255);
Secondly, the variable act was not properly initialized (as mentionned by #JonathanLeffler):
sigset_t mask;
struct sigaction act;
sigemptyset(&mask);
act.sa_handler = &sigint_handler;
act.sa_mask = mask;
act.sa_flags = 0;
Finally, a working code would then be the following:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
void sigint_handler(int h)
{
char message[255] = "Hey! I caught a SIGINT :)\n";
write(1, message, 255);
}
int main()
{
sigset_t mask;
struct sigaction act;
sigemptyset(&mask);
act.sa_handler = &sigint_handler;
act.sa_mask = mask;
act.sa_flags = 0;
if (0 != sigaction(SIGINT, &act, NULL)) {
perror("unable to setup the SIGINT handler!\n");
return 1;
}
while(1) { }
return 0;
}
Hope this helps!

Installing signal handler in C

I am trying to catch a SIGSEGV from my program. I got a problem that my signal_handler doesn't catch the signal.
void handler(int sig){
printf("catch SIGSEGV");
exit(EXIT_FAILURE);
}
void foo(){
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sa.sa_handler = handler;
if(sigaction(SIGSEGV, &sa, NULL) == -1){
handle_error("sigaction");
}
/* if SIGSEGV happen here, I can catch it */
bar();
}
void bar() {
/* if SIGSEGV happen here, I cannot catch it */
}
Is that means I have to install another signal handler inside bar?
But what if I have a bunch of function that want to catch the same signal. I have to install the signal handler for multiple times?
Update :
I tried to install the handler directly in the function but still cannot catch it. So I think it might be other problem. But that pretty weird. I use gdb to run and get
Program received signal SIGSEGV, Segmentation fault.
0x080499b1 in is_printable_string (
str=0xb80fe768 <Address 0xb80fe768 out of bounds>)
at trace/trace.c:259
259 while(str[index]!='\0'){
and this is my is_printable_String
int is_printable_string(char *str){
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = handler;
if(sigaction(SIGSEGV, &sa, NULL) == -1){
handle_error("sigaction");
}
int index;
index=0;
while(str[index]!='\0'){
if(!isprint(str[index])){
return -1;
}
index++;
}
/* continue... */
This seems like I got a SEG fault, but I can't catch it
I intentionally passed that pointer, so nothing wrong with str parameter.
from the man page of sigaction ...
SA_SIGINFO (since Linux 2.2) The signal handler takes three arguments,
not one. In this case, sa_sigaction should be set instead of
sa_handler. This flag is only meaningful when establishing a signal
handler.
Therefore, your issue should be the line
sa.sa_flags = SA_SIGINFO;
Change it to
sa.sa_flags = 0;
and see how it goes.
Indeed as ajcaruana points out your handler doesn't match SA_SIGINFO. But if you are catching SIGSEGV you likely want SA_SIGINFO, to look at the offending address and stuff. In that case your signal handler needs to look like this:
static void
handler(int sig, siginfo_t *si, void *ucontext)
{
/* ... */
}
In particular, you might be interested in si_addr:
For the SIGBUS and SIGSEGV signals, this field contains the address
that caused the invalid memory reference.

Where to declare sig_t signal for SIGPIPE

I'm currently using a kqueue to handle multiple Clients per Thread in a Serverprocess
so I don't want the thread to be terminated when the Signal SIGPIPE appears, i would just like to remove the according socked id from the kqueue.
So My question is: Is there a way to get the according socketid inside a Signalhandle and parse it back to the Process to remove it from the event kqueue or would i have jsut to SIG_IGN the SIGPIPE
and handle the remove by returning of -1 from send? and would it return the -1 value after a timeout time or returns send -1 instantly?
And finally, if the signal ignore is my solution: where id have to put the declaration of the
typedef void (*sig_t) (int);
sig_t
signal(int sig, sig_t func);
Would it have to be in the main function?
or in the beginning of the corresponding thread? or just as global element?
I can't think of an easy way for the signal handler to come to know the current socket being processed unless you are setting some global state each time you do a socket operation.
You can ignore SIGPIPE from main. You do not define your own handler, instead you use SIG_IGN.
signal(SIGPIPE, SIG_IGN);
Or, if you are using sigaction:
struct sigaction act;
act.sa_handler = SIG_IGN;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGPIPE, &act, NULL);
Alternatively, you can issue the MSG_NOSIGNAL flag when you call send. This will suppress the generation of SIGPIPE, and instead generate an EPIPE error (which is what would happen if you ignored SIGPIPE):
ssize_t sent = send(sock, buf, sizeof(buf), MSG_NOSIGNAL);
if (sent > 0) {
/* ... */
} else {
assert(sent < 0);
swtich (errno) {
case EPIPE:
/* ...handle sending on a closed socket */
/* ...handle other error cases */
}
}
'signal( ...' code should be in 'main'.

Resources