-1

I have a signal handler in C++ program:

void term(int signum)
{
    cout << "in term" << endl;
    # Do Stuff
    exit(0);
}

int main(int argc, char *argv[])
{
    # Do Stuff
    signal(SIGINT, term);
    # Do Stuff
}

The program works fine. goes in the function term when I press Ctrl+C and exits.

However, when I try to replicate the behavior using a script, it does not work.

Simplified version of the script I am running:

! /bin/bash
sudo ./program &
rpid=$!

sleep 2
sudo kill -INT $rpid
# sudo kill -TERM $rpid
# sudo kill $rpid

echo "killed"
wait $rpid

The program is does not even go in the term function until I press Ctrl+C. It is stuck on wait indefinitely.

Paulo Tomé
  • 3,782
  • The title asks about the difference between Ctrl-C and kill -INT? The body is about the difference between C and a shell script. OR did I miss-read it (In which case it is confusing). – ctrl-alt-delor Jan 10 '20 at 17:08
  • Even in those small snippets you're doing a lot of dubious things like a) use iostreams in signal handlers b) calling exit(3) from a signal handler c) using signal() (which nobody actually knows how it works) instead of sigaction(2) d) pointlessly using sudo, etc. Please submit a reproducible example. –  Jan 10 '20 at 17:09
  • First you can not (normally) send signals to a process running as root, when not root. And second you can not ctrl-C a process that is running as a background job. – ctrl-alt-delor Jan 10 '20 at 17:12
  • @Mosvy OK so I miss-read it. The problem with the question is that it took two reading. There is a bit where is tells the reader that it is about to show a shell script alternative to the C program. But then we realise that it is an alternative to the manual operation. Well it is ambiguous, so half of readers will go one way, and half the other, on first reading. – ctrl-alt-delor Jan 10 '20 at 17:15
  • you cannot use iostreams or stdio functions inside signal handlers. Replace it with write(1, "in term\n", 8); Anyways, try submitting a complete reproducible example. –  Jan 10 '20 at 17:15
  • It compiles in c++11. Why we cannot use iostream in signal handler? – Nofel Yaseen Jan 10 '20 at 17:20
  • @ctrl-alt-delor the problem is that Ctrl-C will send a SIGINT signal to the entire process group (job), while kill -INT $! will only send it to the process group leader. If sudo is actually waiting for the command it runs (I have no idea whether that's the case), only sudo will be killed, not the child it waits for. –  Jan 10 '20 at 17:21
  • @NofelYaseen because the iostream functions are not signal safe, read man signal-safety –  Jan 10 '20 at 17:22
  • iostream is only present to test if the program goes in the function or not. That is not relevant to the problem. I removed sudo from the program and it works. Any reason why is this case? I still want to run the program as sudo, considering I am sending the signal as sudo. – Nofel Yaseen Jan 10 '20 at 17:29
  • Related: How can bash script do the equivalent of Ctrl-C to a background task?. Key finding: "Thus, when you run a background process (with &) from within a script, it will ignore the SIGINT signal, unless it is trapped. " So sudo is ignoring SIGINT, and your ./program, a child of sudo, cannot undo that. – Mark Plotnick Jan 10 '20 at 17:34
  • @NofelYaseen 1. yes, it is perfectly relevant; if you call unsafe funcs from signal handlers, anything could happen. 2. please read my comment above -- you should send the signal to the whole process group. kill -INT -$! (with the negated pid) may work, but nobody really knows as long as you don't submit a reproducible testcase. –  Jan 10 '20 at 17:35
  • @mosvy I meant irrelevant in the sense, if I remove the line, it still does not work. The answer written and Mark's comment made me understand that I need to get pid of the child to make it work. Thanks everyone! – Nofel Yaseen Jan 10 '20 at 17:47
  • No, you don't need the child of the pid -- you can kill the whole process group, just as Ctrl-C does, by using the negated pid of the process group leader, see the kill(2) manpage. –  Jan 10 '20 at 17:51

1 Answers1

1
% sudo sh -c 'exec echo My process ID is $$.' & echo "Xyr process ID is $\!." ; wait
[1] 59130
Xyr process ID is 59130.
My process ID is 59131.
[1]  + done       sudo sh -c 'exec echo My process ID is $$.'
%

Welcome to the world of Pluggable Authentication Modules! Programs like login, su, and sudo do not overlay themselves with the target program any more.

You are sending your signals to the wrong process.

Further reading

JdeBP
  • 68,745