Why doesnt SIGINT get caught here? - linux

Whats going on here? I thought SIGINT would be sent to the foreground process group.
(I think, maybe, that system() is running a shell which is creating a new process group for the child process? Can anyone confirm this?)
% perl
local $SIG{INT} = sub { print "caught signal\n"; };
system('sleep', '10');
Then hit ctrl+d then ctrl+c immediately and notice that "caught signal" is never printed.
I feel like this is a simple thing... anyway to work around this? The problem is that when running a bunch of commands via system results in holding ctrl+c until all iterations are completed (because perl never gets the SIGINT) and is rather annoying...
How can this be worked around? (I already tested using fork() directly and understand that this works... this is not an acceptable solution at this time)
UPDATE: please note, this has nothing to do with "sleeping", only the fact that the command takes some arbitrary long amount of time to run which is considerably more than that of the perl around it. So much so that pressing ctrl+c gets sent to the command (as its in the foreground process group?) and somehow manages to never be sent to perl.

from perldoc system:
Since SIGINT and SIGQUIT are ignored during the execution of system,
if you expect your program to terminate on receipt of these signals you will need to arrange to do so yourself based on the return value.
#args = ("command", "arg1", "arg2");
system(#args) == 0
or die "system #args failed: $?"
If you'd like to manually inspect system's failure, you can check all possible failure
modes by inspecting $? like this:
if ($? == -1) {
print "failed to execute: $!\n";
}
elsif ($? & 127) {
printf "child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
}
else {
printf "child exited with value %d\n", $? >> 8;
}
Alternatively, you may inspect the value of ${^CHILD_ERROR_NATIVE} with the W*() calls from the POSIX module

I don't quite get what you're trying to achieve here... but have you tried simply comparing to:
perl -wle'local $SIG{INT} = sub { print "caught signal"; }; sleep 10;'
Can you explain what effect you're trying to go for, and why you are invoking the shell? Can you simply call into the external program directly without involving the shell?

Related

How does prctl, set_pdeathsig work in perl?

perl-5.24.0 on RH7
I'd like a forked process to kill itself when it determines that it's parent dies. I've read that I can use Linux::Prctl, set_pdeathsig() to do that. But my test of this doesn't seem to work.
#!/usr/bin/env perl
use strict;
my $pid = fork();
die if not defined $pid;
if($pid == 0) {
do_forked_steps();
}
print "====PARENT===\n";
print "Hit <CR> to kill parent.\n";
my $nocare = <>;
exit;
sub do_forked_steps {
system("/home/dgauthie/PERL/sub_fork.pl");
}
And sub_fork.pl is simply...
#!/usr/bin/env perl
use strict;
use Linux::Prctl;
Linux::Prctl::set_pdeathsig(1);
sleep(300);
exit;
(I believe sending "1" tp set_pdeathsig = SIGHUP. But I also tried "9". Same results)
When I run the first script, I can see both procs using ps in another window. When I hit in the script to kill it, I can see that proc go away, but the second one, the forked process, remains.
What am I doing wrong?
You have three processes, not two, because system forks. They are:
The parent process in the parent script ($pid != 0) which waits on <> and calls exit.
The child process, created by fork in the parent script, which calls system. system forks and then waits for its child to exit before returning.
The child process created by system which execs your child script, calls prctl, and sleeps.
When you press enter, process #1 dies, but process #2 does not, and since process #2 is the parent of process #3, the PDEATHSIG is never invoked.
Changing system to exec in your first script, so that a third process isn't created, causes the PDEATHSIG to fire in your toy problem, but without more information it isn't clear if that's suitable in the "real world" version of what you're trying to do.

Spawn Expect from a perl thread

I am working on a script which needs to spawn an Expect process periodically (every 5 mins) to do some work. Below is the code that I have that spawns an Expect process and does some work. The main process of the script is doing some other work at all times, for example it may wait for user input, because of that I am calling this function 'spawn_expect' in a thread that keeps calling it every 5 minutes, but the issue is that the Expect is not working as expected.
If however I replace the thread with another process, that is if I fork and let one process take care of spawning Expect and the other process does the main work of the script (for example waiting at a prompt) then Expect works fine.
My question is that is it possible to have a thread spawn Expect process ? do I have to resort to using a process to do this work ? Thanks !
sub spawn_expect {
my $expect = Expect->spawn($release_config{kinit_exec});
my $position = $expect->expect(10,
[qr/Password.*: /, sub {my $fh = shift; print $fh "password\n";}],
[timeout => sub {print "Timed out";}]);
# if this function is run via a process, $position is defined, if it is run via a thread, it is not defined
...
}
Create the Expect object beforehand (not inside a thread) and pass it to a thread
my $exp = Expect->spawn( ... );
$exp->raw_pty(1);
$exp->log_stdout(0);
my ($thr) = threads->create(\&login, $exp);
my #res = $thr->join();
# ...
sub login {
my $exp = shift;
my $position = $exp->expect( ... );
# ...
}
I tested with multiple threads, where one uses Expect with a custom test script and returns the script's output to the main thread. Let me know if I should post these (short) programs.
When the Expect object is created inside a thread it fails for me, too. My guess is that in that case it can't set up its pty the way it does that normally.
Given the clarification in a comment I'd use fork for the job though.

bash - How to keep launching a program until it exits with 0

Wrote a python script that does a task that may be running for a few hours. Since it communicates with a remote server, the script may fail if there's a connection error. What I'd like to do is to keep relaunching it if its exit code is not 0. Is it possible with bash?
Some pseudo-C if my wording is not clear:
int exitcode;
do
{
exitcode = MyPythonScript();
} while (exitcode != 0);
until MyPythonScript
do
: Nothing
done
That exits when the command exits with a true (success) status. You can put a sleep, or an error report, or anything else you want in the body of the loop in place of the 'do nothing but always succeed' command :. You can add arguments to the script as desired, of course (and I/O redirections, etc).

Trap command in UNIX

How does the trap command work in this code?
trap "ignore" 2
ignore()
{
main
}
main()
{
trap "main" 2
while [ 1 ]
do
echo -e "\t\t\t1.Add\n\t\t\t2.Remove\n\t\t\t3.Edit\n\t\t\t4.Search\n\t\t\t5.Display\n\t\t\t6.Exit"
echo "Enter the option"
read option
case $option in
1)echo "You take add option";;
2)echo "You take Remove option";;
3)echo "You take Edit option";;
4)echo "You take Search option";;
5)echo "You take Display option";;
6)exit;;
*)echo "Invalid Option"
esac
done
}
main
If the above script is executed, the ctrl+c signal is trapped and the main function is called. But, it is done only only time(first time). It does not work in second time. At first time of ctrl+c, main will be called. But, this works only once. At second time of the ctrl+c, main will not be executed.
That's how signals work in UNIX. When you send a SIGINT using by pressing ctrl + C, the signal handler is called i.e. in your case, the main function. But when the handler is processing the signal, all the subsequent signals are blocked until the handler returns. In your case, the handler never returns. So your program can't react to the subsequent SIGINT signals until the handler returns. It's not a good idea to call a signal handler recursively and a signal handler shouldn't do too much of work either. It should process the signal and return as soon as it can.
Also, note that the defined macro names such as SIGINT should be used for better portability than the actual numbers. You can get the list using kill -l or trap -l commands.

after calling exec

After calling exec, is it possible to print a message, because I tried and nothing happened. I read some articles about exec but I couldn't find my answer. It replaces the process image with a new one but not creating a new process. Is it something about it? Does it wait for something I mean if I use it in child process, so does it wait for ending child process?
I can give this example:
char *args[6] = { "cat","-b","-t","-v",argv[1],0};
else if(pid == 0){
printf("Child Process ID:%d, Parent ID:%d, Process
Group:%d\n",getpid(),getppid(),getgid());
execv("/bin/cat",args);
printf("AHMET TANAKOL\n");
}
The exec family, like you already read, replaces the process image. That is, it loads the new program, removes your program, and start running the new program in place of your program.
No call to exec functions ever returns, unless there is an error.

Resources