Why the signal handler doesn't process the signal - c

I'm trying to make a program that simulates the command nohup. The program gets as a first parameter, the name of a command that is gonna be executed.
The program executed by my program must not be notified when the terminal is closed, it will have to ignore the SIGHUP.
If I test my program with with the following command:
./mynohup sleep 120 &
And then I try to send a SIGHUP from another terminal, sleep terminates when it should be immune to it.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include "utils.h"
#define NOHUP_OUT_FILE "nohup.out"
static void handle_signal(int signum)
{
if(signum == SIGHUP)
{
printf("This is ignored\n");
}
else
{
printf("Not ignored\n");
}
fflush(stdout);
}
/* configure handlers */
static void set_signals(void)
{
struct sigaction sa;
int rc;
/* TODO - ignore SIGHUP */
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = handle_signal;
rc = sigaction(SIGHUP, &sa, NULL);
DIE(rc == -1, "sigaction");
}
/* execute a new program */
static void exec_func(int argc, char **argv)
{
int rc;
int i;
char **exec_args;
int fd;
set_signals(); /* ignore SIGHUP */
if(isatty(STDOUT_FILENO))
{
fd = open(NOHUP_OUT_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
DIE(fd < 0, "open");
dup2(fd, STDOUT_FILENO);
close(fd);
}
/* exec a new process */
exec_args = malloc(argc * sizeof(*exec_args));
DIE(exec_args == NULL, "malloc");
for (i = 0; i < argc-1; i++)
exec_args[i] = argv[i+1];
exec_args[argc-1] = NULL;
execvp(exec_args[0], exec_args);
DIE(1, "execvp");
}
int main(int argc, char **argv)
{
if (argc <= 1) {
fprintf(stderr, "Usage: %s command_and_arguments\n", argv[0]);
exit(EXIT_FAILURE);
}
exec_func(argc, argv);
return 0;
}
I tried to skip creating a new process and the signal handler works great.
If the signal handler is in the following form the program works
static void set_signals(void)
{
struct sigaction sa;
int rc;
/* ignore SIGHUP */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_IGN;
rc = sigaction(SIGHUP, &sa, NULL);
DIE(rc == -1, "sigaction");
}
I don't understand why when I create the first version of the signal handler the program doesn't works and with the second one it works.
Thanks in advance!

All exec functions reset the dispositions of caught signals to their default dispositions.
When you exec, your process image is destroyed and replaced by the process image of the new program. In it, the pointer to the handle_function you passed to sigaction no longer has meaning, or the old meaning at least. The only sensible thing the OS can do with handled signals upon execve is to reset them.
The meaning of SIG_IGN is universal and independent of the current program and that's why SIG_IGN can be, and is, inherited.

execvp() is a front end for the execve() syscall.
From its linux manpage:
All process attributes are preserved during an execve(), except the following:
* The dispositions of any signals that are being caught are reset to
the default (signal(7)).
So the signal handler you installed is reset.

CORRECTION: (see history of changes for original text)
The nohup(1) program just shifts the progran name (nohup) and the options to it, from the argc/argv parameters to main, redirects stdout/stderr to a file (nohup.out) in case one or both are directed to a tty device, and then just ignores SIGHUP and execvp(*argv, argv); for the original program to execute. It even does no fork(2) at all.
The source code of FreeBSD nohup is available here.

Related

Forward all user-input to Linux PTY in subprocess

Background
I'm trying to build a wrapper for the shell. Running in a TTY, it spawns the regular shell in a child process via forkpty. The intent is for all user input to be forwarded to the child process as-is, but to intercept the child's output and do some processing on it before copying it to the parent process' stderr. The user should be able to forget that the shell is wrapped at all, apart from the augmented output.
Problem
I can't figure out how to transparently forward the input. Here's the gist of my code currently (error checks and minor details omitted). It should compile with gcc <filename> -pthread -lutil:
#include <stdbool.h>
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <pty.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/wait.h>
#define BUF_SIZE 512
#define EOT "\x04" // ASCII end-of-transmission (i.e. 'EOF').
void * tty_input_routine(void * arg);
void tty_output_routine();
int parent_term_fd;
volatile sig_atomic_t got_sigchld = 0;
volatile sig_atomic_t got_sigwinch = 0;
// Listens for the child to exit, and causes the parent to exit.
void handle_sigchld(int sig) {
got_sigchld = 1;
}
// Listens for the parent to be resized, and causes the child to be resized.
void handle_sigwinch(int sig) {
got_sigwinch = 1;
}
void main() {
/* Block SIGWINCH and SIGCHLD. They are later unblocked via pselect in the main loop. */
sigset_t sigmask;
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGWINCH);
sigaddset(&sigmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &sigmask, NULL);
/* Establish signal handlers. */
struct sigaction sig_action;
sig_action.sa_flags = 0;
sig_action.sa_handler = &handle_sigchld;
sigemptyset(&sig_action.sa_mask);
sigaction(SIGCHLD, &sig_action, NULL);
sig_action.sa_handler = &handle_sigwinch;
sigaction(SIGWINCH, &sig_action, NULL);
/* Get the initial terminal size. */
struct winsize term_sz;
ioctl(STDERR_FILENO, TIOCGWINSZ, &term_sz);
/* Turn off input echo in the child terminal since the parent should do that. */
struct termios term_ios;
tcgetattr(STDERR_FILENO, &term_ios);
term_ios.c_lflag &= ~(ECHO);
/* Do the fork. */
pid_t child_pid = forkpty(&parent_term_fd, NULL, &term_ios, &term_sz);
if (child_pid == 0) {
/* This is the child process. Execute the shell. */
char *const argv[] = { NULL };
execvp("/bin/bash", argv);
}
/* This is the parent process.
* Spawn a dedicated thread to forward input to the child PTY.
* The main thread will be used to process the output. */
pthread_t input_thread;
pthread_create(&input_thread, NULL, &tty_input_routine, NULL);
tty_output_routine(parent_term_fd);
}
void * tty_input_routine(void * arg) {
struct termios tcattr;
tcgetattr(STDIN_FILENO, &tcattr);
// cfmakeraw(&tcattr); // This doesn't seem to help.
// tcattr.c_lflag &= ~ICANON; // Neither does this...
tcsetattr(STDIN_FILENO, TCSAFLUSH, &tcattr);
char buf[BUF_SIZE];
fd_set fds;
FD_ZERO(&fds);
while (true) {
FD_SET(STDIN_FILENO, &fds);
if (select(STDIN_FILENO + 1, &fds, NULL, NULL, NULL) == -1) {
if (errno == EINTR) {
continue; // A signal was caught; just try again.
}
// Otherwise, some error...
puts("THIS IS UNEXPECTED");
break;
} else {
ssize_t bytes = read(STDIN_FILENO, buf, BUF_SIZE);
if (bytes > 0) {
write(parent_term_fd, buf, (size_t)bytes);
} else if (bytes == 0) {
/* End of transmission? */
write(parent_term_fd, EOT, 1);
break;
}
}
}
return NULL;
}
void tty_output_routine() {
fd_set fds;
FD_ZERO(&fds);
sigset_t empty_sigmask;
sigemptyset(&empty_sigmask);
char buf[BUF_SIZE];
while (true) {
FD_SET(parent_term_fd, &fds);
if (pselect(parent_term_fd + 1, &fds, NULL, NULL, NULL, &empty_sigmask) == -1) {
if (errno == EINTR) {
/* A signal was caught. */
if (got_sigwinch) {
got_sigwinch = 0;
struct winsize term_sz;
ioctl(STDERR_FILENO, TIOCGWINSZ, &term_sz);
/* This sends SIGWINCH to the child. */
ioctl(parent_term_fd, TIOCSWINSZ, &term_sz);
}
if (got_sigchld) {
// This should run when the user does CTRL+D, but it doesn't...
puts("THIS IS THE PROPER EXIT");
return;
}
} else {
// Otherwise, some error...
break;
}
} else {
ssize_t bytes = read(parent_term_fd, buf, BUF_SIZE);
// (Omitted) do some processing on the buffer.
write(STDERR_FILENO, buf, (size_t)bytes);
}
}
}
The idea is that when the user hits CTRL+D, the input routine will read an empty buffer, and send EOT to the child, which will exit, causing SIGCHLD to fire in the parent, which will also exit. However, SIGCHLD is never raised in the parent, even though bash definitely exits as shown by the fact that it prints exit to the screen. Confusingly, SIGWINCH appears to be handled just fine.
Furthermore, the parent has trouble forwarding CTRL+C to the child. Even if I add another signal handler for SIGTERM and simply forward that signal to the child via kill, the shell itself exits, as opposed to whatever's running in the shell, as bash does normally. I'm not sure what to do differently here.
I've tried cfmakeraw and turning off canonical mode (ICANON) but this makes the program even more broken. Perhaps there are some other terminal attributes I'm missing?
It feels like I'm over-engineering this, since all I want to do is essentially trick the child process into accepting input as though it had no wrapping parent process. Do I really have to handle everything explicitly in the parent and manually forward user input and signals to the child? How can I do this in a way that the user can't tell that the shell is wrapped, apart from the augmented output?

how to immediately wake up the daemon by sending him a SIGUSR1 signal

I wrote a program deamon which copy files with one folder to another .I have to implement SIGUSR1 which immediately wake up the daemon by sending him a SIGUSR1 signal. I do not know what I did wrong ,I use command kill -SIGUSR1 ,maybe wrong command?.Somebody know what is wrong with this code ?I did not have any warning after compiled this program,but just nothing happend
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
#define _XOPEN_SOURCE ;
int recursion = 0; //1 if enabled, otherwise 0
int sleepTime = 300;
int fileLimit = 0;
int signaL = 0;
int exitSignal = 0;
int buffer = 1000;
//Returns 0 if arguments are correct otherwise returns 1
int readArguments(int number, char **argv, char *source, char *goal);
int checkFileType(struct stat file);
int copy(char *source, char *target, mode_t mask);
int copy_map(char *source, char *target, struct stat *Source);
void syncCopy(char *source, char *target);
void syncRemove(char *source, char *target);
void my_handler(int sig)
{
syslog(LOG_INFO, "Daemon received signal SIGUSR1\n");
signaL = 1;
}
void exitFunction(int sig)
{
syslog(LOG_INFO, "Daemon received signal SIGUSR2\n");
exitSignal = 1;
}
int main(int argc, char **argv)
{
//char tables for paths
char source[500], goal[500];
struct stat Source, Goal;
struct sigaction my_action, old_action;
//checking and reading arguments
if (readArguments(argc, argv, source, goal) == 1)
exit(-1);
//checking paths
//checking if argv[1] and argv[2] are existing paths
if (lstat(source, &Source) != 0 || lstat(goal, &Goal) != 0) //bad result
{
printf("One of the paths or both dont exist\n");
exit(-1);
}
if (checkFileType(Source) != 0)
{
printf("Source path is not path to folder");
exit(-1);
}
if (checkFileType(Goal) != 0)
{
printf("Goal path is not path to folder");
exit(-1);
}
//forking the parent process
pid_t pid;
// Fork off the parent process and create new
pid = fork();
//if failure
if (pid < 0)
{
exit(-1);
}
// if it is native process
else if (pid > 0)
{
return 0;
}
//if pid==0 then it is childs process
//now we have to umask in order to write to any files(for exmaple logs)
umask(0);
openlog("logFile", LOG_PID, LOG_DAEMON);
syslog(LOG_INFO, "Deamon has just started running\n");
pid_t sid = setsid();
if (sid < 0)
{
syslog(LOG_ERR, "Error with session opening\n");
exit(-1);
}
//SIGNAL SIGUSR1
my_action.sa_handler = my_handler;
sigfillset(&my_action.sa_mask);
my_action.sa_flags = 0;
if (sigaction(SIGUSR1, &my_action, &old_action) < 0)
{
syslog(LOG_ERR, "Error with the use of SIGUSR1 signal\n");
exit(-1);
}
//SIGNAL SIGUSR2 for exiting daemon
my_action.sa_handler = exitFunction;
sigfillset(&my_action.sa_mask);
my_action.sa_flags = 0;
if (sigaction(SIGUSR2, &my_action, &old_action) < 0)
{
syslog(LOG_ERR, "Error with the use of SIGUSR2 signal\n");
exit(-1);
}
while (!exitSignal)
{
sleep(sleepTime);
switch (signaL)
{
case 0:
syslog(LOG_INFO, "Demon started working after %ds\n", sleepTime);
break;
case 1:
{
syslog(LOG_INFO, "Demon started working after SIGUSR1 signal\n");
signaL = 0; //Need to reeset signaL
break;
}
}
syncCopy(source, goal);
syncRemove(source, goal);
syslog(LOG_INFO, "Demon has just gone to sleep");
}
//at the end of program we need to close log using
syslog(LOG_INFO, "Demon has stopped\n");
closelog();
return 0;
}
Use command as kill -10 <pid> for SIGUSR1 and kill -12 <pid> for SIGUSR2.
kill -l // command to know the signal number.
Also make variable signaL , exitSignal as volatile sig_atomic_t type.
WHY volatile?
when a global variable updated in signal handler is periodically checked in some other function for appropriate action, we should always declare them using the volatile attribute in order to prevent the compiler from performing optimizations that result in the variable being stored in a register. In worst case, updated value of variable(updated in handler context) won't be visible to function polling for the variable.
WHY sig_atomic_t?
Reading and writing global variables may involve more than one machine- language instruction, and a signal handler may interrupt the main program in the middle of such an instruction sequence. (We say that access to the variable is nonatomic.) For this reason, the C language standards and SUSv3 specify an integer data type, sig_atomic_t, for which reads and writes are guaranteed to be atomic. Thus, a global flag variable that is shared between the main program and a signal handler should be declared as follows:
volatile sig_atomic_t signaL;

macOS `sigaction()` handler with `SA_SIGINFO` does not include `si_pid`

I'm trying to write a signal handler which needs to know the pid of the process that sends the signal. I'm having no luck with getting anything useful from the siginfo_t passed into my handler on macOS 10.14 with Xcode 10.
I've reduced my code to the below minimal sample to demonstrate the issue. In this sample I spawn a child process to send the signal I want to test which is defaulted to SIGTERM, but no other signal I've tried works any better.
Assuming you want to build and test this on a mac, you probably want to tell lldb to not stop when receiving a signal. You can use this lldb command: pro hand -p true -s false SIGTERM.
I'm also compiling with C++, but I believe I have excised all of that and the sample code should be pure C now.
Note that it doesn't matter if the signal originates from a child, terminal, or another process the result is always that si_pid is always 0 (along with everything other than the si_signo and si_addr). It doesnt matter how many times I send the signal, so it seems to not be simply a race condition.
How can I get the pid of the process sending the signal on macOS 10.14? I don't recall having this issue on 10.12 which is what I was using before.
This is just a sample to demostrate the problem, so please ignore anything that isn't actually causing a problem.
If the code seems like it should work as I expect, then I would be interested in seeing comments about systems that it works on too.
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
volatile sig_atomic_t histogram[3] = {0,0,0};
volatile sig_atomic_t signaled = 0;
const int testsig = SIGTERM;
void sigaction_handler(int sig, siginfo_t* info, void* context)
{
switch (info->si_pid) {
case 0:
case 1:
histogram[info->si_pid]++;
break;
default:
histogram[2]++;
break;
}
signaled = 1;
}
int main(int argc, const char * argv[]) {
pid_t mainpid = getpid();
pid_t pid = fork();
if (pid == 0) {
while (kill(mainpid, 0) == 0) {
sleep(1);
kill(mainpid, testsig);
}
_exit(0);
}
struct sigaction sigAction;
memset( &sigAction, 0, sizeof( sigAction ) );
sigAction.sa_sigaction = sigaction_handler;
sigemptyset (&sigAction.sa_mask);
sigAction.sa_flags = SA_SIGINFO;
sigaction(testsig, &sigAction, NULL);
while (1) {
if (signaled) {
printf("pid 0: %d, pid 1: %d, others: %d\n", histogram[0], histogram[1], histogram[2]);
signaled = 0;
}
sleep(1);
}
}
I'm currently using macOS Mojave 10.14.1.
How can I get the pid of the process sending the signal on macOS
10.14? I don't recall having this issue on 10.12 which is what I was using before.
The following code meets your wish simply. If you send SIGTERM, you can see pid of sender process.
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
static void hdl (int sig, siginfo_t *siginfo, void *context)
{
printf ("Sending PID: %ld, UID: %ld\n",
(long)siginfo->si_pid, (long)siginfo->si_uid);
}
int main (int argc, char *argv[])
{
struct sigaction act;
fprintf(stderr, "%i pp %i\n",getpid(), getppid());
memset (&act, '\0', sizeof(act));
/* Use the sa_sigaction field because the handles has two additional parameters */
act.sa_sigaction = &hdl;
/* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler. */
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGTERM, &act, NULL) < 0) {
perror ("sigaction");
return 1;
}
while (1)
sleep (10);
return 0;
}
For your code,
Rule of thumb: Don't forget to carry burial procedures out even though you are sure that child process ends prior parent process. By invoking wait(...) you tell the operating system that I'm done my things for my child so now you can clean allocated fields etc.
I'd prefer initialize signal utilities prior forking what if the parent process doesn't have a chance to register signal action? Moreover, I don't understand why you handle 0 and 1 cases in switch. Intrinsically the cases aren't hit, so always omitted.
In addition, you didn't use break in your if condition within main(). It doesn't go in if after a while yet the following circumstance which is not anticipated and desirable is that the program stays forever in while() loop. I'd prefer to put signaled into condition of while() loop.
At last but not least, due to sleep() call in child process until signaled is turned out 0, SIGTERM is caught several times successfully. When signaled is 0, the loop stops.
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <memory.h>
#include <sys/wait.h>
volatile sig_atomic_t histogram[3] = {0,0,0};
volatile sig_atomic_t signaled = 0;
const int testsig = SIGTERM;
void sigaction_handler(int sig, siginfo_t* info, void* context)
{
switch (info->si_pid) {
case 0:
case 1:
histogram[info->si_pid]++;
break;
default:
fprintf(stderr, "sender pid -> %i\n", info->si_pid);
histogram[2]++;
break;
}
signaled = 1;
}
int main(int argc, const char * argv[]) {
struct sigaction sigAction;
memset( &sigAction, 0, sizeof( sigAction ) );
sigAction.sa_sigaction = sigaction_handler;
sigemptyset (&sigAction.sa_mask);
sigAction.sa_flags = SA_SIGINFO;
sigaction(testsig, &sigAction, NULL);
pid_t mainpid = getpid();
pid_t pid = fork();
if (pid == 0) {
fprintf(stderr, "my pid -> %i parent's pid-> %i\n", getpid(), getppid());
if (kill(mainpid, 0) == 0) { // signals are not queued not need loop
sleep(1);
kill(mainpid, testsig);
}
_exit(0);
} else {
wait(NULL); // play with this line to see what the difference is
while ( signaled ) {
printf("pid 0: %d, pid 1: %d, others: %d\n", histogram[0], histogram[1], histogram[2]);
signaled = 0;
sleep(1);
}
// wait(NULL); // play with this line to see what the difference is
}
}
It turns out that debugging via Xcode LLDB is the culprit. If I build and run the program normally it works fine. If I find out why I will update this answer.
I already have the "PASS" set for SIGTERM in lldb as noted in the question, so it seems like somehow there is a bug in the version of lldb shipped with Xcode 10.0 and it is "passing" the signal by creating a new struct and setting the signal number rather then the structure that would have normally been received. As I stated before this did used to work fine in whatever version of lldb shipped with macos 10.12
If somebody has a better explaination, please post an answer and I will accept and award bounty.

How do I call other functions with the signal function?

I got a Synthasizer yesterday as a gift, and was interested in writing data to it. I got this much working, here is a program that scales through some notes.
Then I thought it would be neat to have it catch the Ctrl+C singal, and close.
The problem with just closing the file descriptor is that the MIDI device still processes the last note it was given, so I wrote the mute function, which tells the midi device to mute. That works.
so then I tried to have the signal handler mute the device before exiting, and I have been struggling ever since. The signal(SIGINT, intHandler); function wont take additional arguments. So I thought I would be clever, and write a function mySig that calls the signal function and takes the device file descriptor, and data pointer, and would be able to do one last write, before exiting.
IDK, that might even work, but mySig function, seems to be called from the start, and scaling never happens.
How can I call my mute function, before exiting the program with the signal function?
This is my first signal handing program, Im running linux, and the program is in C.
#include <sys/soundcard.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
static volatile int keepRunning = 1;
char* device = "/dev/midi1";
//function headers:
void mute(int fd, char *data);
void intHandler(int dummy);
void mySig(void (*intHandler)(int dummy), int fd, char *data);
int main(void){
unsigned int note=50;
char data[3] = {0x90, note, 33}; //device address, note, volume
int fd = open(device, O_WRONLY, 0);
if( fd < 0 ){
printf("Error: cannot open Synth %s\n", device);
exit(1);
}
signal(SIGINT, intHandler);
// mySig(intHandler,fd,data);
while(keepRunning){
for( note=30; note < 95; note++ ){
data[1]=note;//change note
write( fd, data, sizeof(data) );
usleep(100000);
if(note>=89){
note =30;
}
}
mute(fd,data); //mutes the data stream.
close(fd); // close device
return 0;
}
}
//functions:
void mute(int fd, char *data){
data[2]=0;//setVolume to 0
write(fd, data, sizeof(data));
close(fd);
}
void mySig(void (*intHandler)(int dummy), int fd, char *data){
printf("my Sig has been called\n");
mute(fd,data);
signal(SIGINT, intHandler);
}
void intHandler(int dummy) {
printf("my Sig has been called\n");
keepRunning = 1;
printf("ctrl+c was pressed, exiting\n");
usleep(10000);
exit(1);
}
Use the signal handler to only clear your keepRunning flag.
Personally, I prefer the opposite flag, as in done:
static volatile sig_atomic_t done = 0;
static void done_handler(int signum)
{
done = 1; /* Or, in Linux, done = signum. */
}
static int install_done(const int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = done_handler;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
If the user runs the program in a terminal, and they close the terminal unexpectedly, the program will receive a SIGHUP signal; Ctrl+C causes a SIGINT signal; and SIGTERM is often used to ask a program to exit. So, I personally like to do
if (install_done(SIGINT) ||
install_done(SIGHUP) ||
install_done(SIGTERM)) {
fprintf(stderr, "Cannot install signal handlers: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
early in my main().
All you need to do, is to have your loop -- in my case,
while (!done) {
/* Play notes or whatever */
}
and after the loop, mute the last note played, then close the device.
Consider the signal just a request to exit, as soon as is convenient; not a demand to exit immediately. It is expected that programs do necessary cleanup when they receive a signal asking them to exit. If one wants a program to exit right then, one can always kill the process with SIGKILL.

Can't trap SIGTERM with sigaction function

I compiled the program. Starting it and waiting. I open the other terminal, and kill the any running program with command "kill pid" or "kill -15 pid" or "kill -SIGTERM pid" (replace PID with the actual process ID). The killed program is exit, but can't trap SIGTERM to print "done.".
I copy code here: https://airtower.wordpress.com/2010/06/16/catch-sigterm-exit-gracefully/.
Can I help you? I am appreciated all answers.
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
volatile sig_atomic_t done = 0;
void term(int signum)
{
done = 1;
}
int main(int argc, char *argv[])
{
struct sigaction action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_handler = term;
sigaction(SIGTERM, &action, NULL);
int loop = 0;
while (!done)
{
int t = sleep(3);
/* sleep returns the number of seconds left if
* interrupted */
while (t > 0)
{
printf("Loop run was interrupted with %d "
"sec to go, finishing...\n", t);
t = sleep(t);
}
printf("Finished loop run %d.\n", loop++);
}
printf("done.\n");
return 0;
}
You need to setup your signal handler correctly in order to handle signals you want to catch. This is how I do my signal handler:
static void handle_signal(int signum); //in header, then implement
//in the source file
struct sigaction myaction;
myaction.sa_handler = handle_signal;
myaction.sa_flags = 0; //or whatever flags you want but do it here so the signals you register see these flags
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGTERM);
sigaction(SIGTERM, &myaction, NULL);
myaction.sa_mask = mask;
I am able to catch SIGTERM as well as all the other signals I register there (to sigaddset and sigaction).

Resources