From: max@spam.uchicago.edu (Max Ziff)
Subject: Re: kill the shell script?!
Organization: Center for Information and Language Studies / University of
	Chicago
	<1992Apr14.171312.25132@news.eng.convex.com>
Date: Wed, 15 Apr 1992 22:12:05 GMT

In article <1992Apr14.171312.25132@news.eng.convex.com> Tom Christiansen <tchrist@convex.COM> writes:
   From the keyboard of max@spam.uchicago.edu (Max Ziff):
   :I'm working in a team, and I'm responsible for a module that presents
   :as interface the standard unix shell-callable process interface:
   :namely it takes a few command-line options, but primarily takes its
   :input from stdin and writes its output to stdout.
   :
   :However, the caller of this process is not a shell, it's (at the
   :moment) a perl script.  It's important that this caller be able to
   :kill the process I'm responsible for (and all its children--there's
   :the rub).

   I'd have the parent perl script arrange it, so that it knows whom
   to kill.  This demos the idea:


       #!/usr/local/bin/perl
       setpgrp(0,0) || die "setpgrp: $!";
       if (fork) { # i am the parent
	   sleep 2;
	   kill -1, $$;  # killpg -HUP 
	   die "can't get here";
       } else {  # i am the child
	   while (1) {
	       print "i am a kid ", ++$i, "\n";
	   }
	   die "can't get here either";
       }

   Replace the child portion with the system("my_shell_script args") and
   the killpg should get that script and any of its (well-behaved) kids.

   --tom

The above kills the (well-behaved) kids but it also kills the parent.
I want the parent to be able to kill the kids but stay alive itself.
So the parent shouldn't be in the same process group as the child.

So I tried wrapping the above suggestion around my shell script.  I
left the original parent perl script untouched and tried:

#!/usr/local/bin/perl
setpgrp(0,0) || die "setpgrp: $!";
exec 'my-original-shell-script', @ARGV;

Well that doesn't quite work.  It does achieve the goal of having the
script be process leader to all its (well-behaved) kids, but when the
parent kills that process leader, the signal doesn't propogate to the
rest of the group.  I suppose this means that the parent wasn't
killing the child with killpg(2) (or with that variant of kill(2)
which amounts to the same thing).  I think I'm wandering into a sysV
vs. BSD thing here?  By the way, it seems also that you can't depend
on being able to send a kill signal to a process group from the shell;
at least, the various shells are not at all uniform in this respect.

The effect I want is that the parent shouldn't have to know or care
whether the child is process leader or what: I just want the parent to
be able to kill the child in the dumbest, most portable way, and have
the net effect be that the child and all its (well-behaved) kids also
die.

This seems to fill the bill, at the expense of another process:

#!/usr/local/bin/perl
sub handler {  # 1st argument is signal name
    local($sig) = @_;
    $SIG{'INT'} = 'DEFAULT'; # restore default action
    kill -1, $$;  # killpg -HUP
    exit(0);
}

$SIG{'HUP'} = 'handler';
$SIG{'INT'} = 'handler';
setpgrp(0,0) || die "setpgrp: $!";
if (fork) { # i am the parent
    wait;
} else {  # i am the child
    exec 'my-original-shell-script', @ARGV;
    die "can't get here";
}

Is there a better solution?
--
Donald Ziff (Max)         Center for Information and Language Studies
                          1100 E. 57th Street, Chicago, Illinois   60637
                          ziff@cs.uchicago.edu