Propagation of the signal to the parent when using the system

I wrote a wrapper script that runs another script using system() . The child script traps SIGINT and handles the exception internally. Therefore, it should not distribute SIGINT its parent when exiting it. However, in some cases, the parent still receives SIGINT . For example ( parent.pl ):

 use feature qw(say); use strict; use warnings; use POSIX (); my @data = (q(child.pl 'dummy'), q(child.pl), q(bash -c child.pl), q(sh -c child.pl)); for ( @data ) { say "Running command '$_'.."; my $res = system $_; my $signal = $res & 127; my $rval = $res >> 8; say "Parent received return value: $rval"; if ( $signal == POSIX::SIGINT ) { say "Parent received SIGINT"; } } 

and child.pl :

 use feature qw(say); use strict; use warnings; eval { local $SIG{INT} = sub { die "Aborted by user.\n" }; sleep 10; }; if ( $@ ) { print "\n" . $@ ; exit 0; } say "Timed out.."; exit 1; 

If I press CTRL-C before the timeout expires, the output is as follows:

 Running command 'child.pl 'dummy''.. ^C Aborted by user. Parent received return value: 0 Parent received SIGINT Running command 'child.pl'.. ^C Aborted by user. Parent received return value: 0 Running command 'bash -c child.pl'.. ^C Aborted by user. Parent received return value: 0 Running command 'sh -c child.pl'.. ^C Aborted by user. Parent received return value: 0 Parent received SIGINT 

So, in the first and last case, the parent receives SIGINT , while for the second and third cases this is not so.

What is the reason for this? And how can it be fixed so that SIGINT is not distributed for the first and last case?

(I suspect this is due to the Shell type, i.e. sh vs bash )

+2
perl
source share
1 answer

First, let's know what is being done.

 system($shell_command) 

not suitable for

 system({ "/bin/sh" } "/bin/sh", "-c", $shell_command) 

if the shell command does not contain shell metacharacters, but spaces, in this case

 system($shell_command) 

not suitable for

 my @cmd = split(' ', $shell_command); system({ $cmd[0] } @cmd) 

Thus,

 system("child.pl 'dummy'") is short for system({ "/bin/sh" } "/bin/sh", "-c", "child.pl 'dummy'") system("child.pl") is short for system({ "child.pl" } "child.pl") system("bash -c child.pl") is short for system({ "bash" } "bash", "-c", "child.pl") system("sh -c child.pl") is short for system({ "sh" } "sh", "-c", "child.pl") 

It should be noted that bash replaces itself with child.pl instead of propagating it in a separate process in this particular case. This makes child.pl direct child of parent.pl in the third case (as in the second case).


Secondly, let's know what Ctrl-C does.

When Ctrl-C is pressed, the terminal sends SIGINT to each process that has this terminal as the control terminal. In other words, SIGINT is sent to each session process.

As you can see, adding system("ps -o pid,ppid,pgrp,sid,cmd"); in child.pl , there are three or four processes in our session, depending on the test case.

  • child.pl : child.pl handles SIGINT. He is not killed by him.
  • The shell started by parent.pl in test cases 1 and 4: the shell is killed by SIGINT.
  • parent.pl : system makes the equivalent of local $SIG{INT} = 'IGNORE'; so it ignores sigint.
  • Login shell starting parent.pl : it ignores SIGINT, but I don't know why. I assume this is an interactive shell.

So this is what you are observing:

  • When the (direct) child element of parent.pl is child.pl [Test Examples 2 and 3], the child element ( child.pl ) does not die from SIGINT, since it processes SIGINT.
  • When the (direct) child element of parent.pl is the shell [Test cases 1 and 4], the child element (shell) dies from SIGINT because non-interactive shells do not process / ignore SIGINT.
+2
source share

All Articles