[comp.lang.perl] Problem with waitpid?

okamoto@hpcc01.HP.COM (Jeff Okamoto) (12/06/90)

I'm having a strange problem and I'm hoping someone out there may be
able to help me.

What I'm trying to do is write a perl script that will handle all the
myriad daily cleanup things that need to be done.  I envisioned having
a single file which contains the names of programs and/or scripts.
The perl program would execute each of these in turn, collecting the
stdout and stderr from them, sending the stdout and/or stderr to each
"owner" of a particular script.

To this end, I've written a perl library which handles the ugly task
of fork/exec/waiting and collecting the stdout and stderr.  It is
enclosed below.  (Notice the waitpid call.  I don't recall when it
first made its appearance.)

The actual problem I'm having is that one of the scripts that I fire
off becomes defunct and the perl library doesn't catch it.  Thus the
perl script hangs until I kill it.  I've confirmed that the PID that
the perl library starts up is the same as the defunct PID, and that it
is (was) the script in question.

I can actually get the shell script to work IF I don't call ANOTHER
script which starts up a daemon (to handle networked software
installation).  The flow of control is thus:

	nightly (the original perl script)
	   |
	   | <--- nightly.cf (it's configuration file)
	   V
	n.test (contained in nightly.cf)
	   |
	   V
	startinstall (called from n.test)
	   |
	   V
	installd (the daemon mentioned above)

I've confirmed that it's the attempt to start up installd that is
the problem.  Installd is a "well-behaved" daemon in that it
disassociates itself from the control terminal, resets its process
group, etc.

I'm running patchlevel 41 on a 7.0 HP-UX machine.

I'd really appreciate any suggestions or help that anyone could give.
-- 
 \      oo	The New Number Who,
  \____|\mm	Jeff Okamoto
  //_//\ \_\	HP Corporate Computing & Services
 /K-9/  \/_/	okamoto@ranma.corp.hp.com
/___/_____\	
-----------	(415) 857-6236
-----Begin file
;#
;# Perl library to fork/exec a program and return the standard out
;# and standard error in a list
;#
;# Jeff Okamoto
;#
;# $Header: execute.pl,v 1.1 90/10/17 15:11:38 okamoto Exp $

;# Parameters:
;#
;# In:	$program is a string that contains the command line of the
;#	program to run.
;#	$uid is the UID to run the program as.  If $uid == -1, it is
;#	run as the invoking UID.
;# Out:	*retp is a list that will contain the standard out and
;#	standard error of the program.  *retp should be empty
;#	before execute is called.
;# Return value: The high eight bits of the wait return value
;#	are returned.

sub execute {

	local($program) = shift(@_);	# Program to run
	local($uid) = shift(@_);	# Uid to run program as
local($debug) = shift(@_);
	local(*retp) = shift(@_);	# Array to hold stdout/stderr
	local($pid);			# Hold child pid
	local($rv);			# Hold return from wait
local(@temp);


push(@retp, "Here I am!\n");
	if (! pipe(TOREAD, TOWRITE)) {
		push(@retp, "Pipe failed: $!");
		$| = $oldbuffer;
		return(-1);
	}

	$pid = fork;
	if ($debug) { push(@retp, "Fork'ed PID was $pid.\n"); }
	if ($pid == -1) {
		push(@retp, "Fork failed: $!");
		close(TOREAD);
		close(TOWRITE);
		$| = $oldbuffer;
		return(-1);
	}

	if ($pid == 0) {

		close(TOREAD);
		close(STDOUT); open(STDOUT, ">&TOWRITE");
		select(STDOUT); $| = 1;
		close(STDERR); open(STDERR, ">&TOWRITE");
		select(STDERR); $| = 1;
		close(TOWRITE);

		if ($uid != -1) {
			# Try to change uid
			$> = $uid;
			if ($> != $uid) {
				printf STDERR "Setuid failed: $!";
				exit(-2);
			}
		}

		exec ("$program");
		printf STDERR "Can't exec: $!";
		exit(-1);

	} else {

		close(TOWRITE);

		@temp = <TOREAD>;	# Slurp up the output.
		push(@retp, @temp);
		close(TOREAD);
		$whodied = waitpid($pid, 0);	# Wait for the correct child
		$rv = $? >> 8;
		if ($debug) {
			$r = sprintf("Reaped PID %d, status = %o\n",
			     $whodied, $?);
			push(@retp, $r);
		}

	}

	return($rv);
}

1;
-----End file

okamoto@hpcc01.HP.COM (Jeff Okamoto) (12/14/90)

I wrote a while ago:

> What I'm trying to do is write a perl script that will handle all the
> myriad daily cleanup things that need to be done.  I envisioned having
> a single file which contains the names of programs and/or scripts.
> The perl program would execute each of these in turn, collecting the
> stdout and stderr from them, sending the stdout and/or stderr to each
> "owner" of a particular script.

I got one piece of mail and that's it.  I can't believe no one else
might not have any more suggestions.  Perhaps it just didn't make it
out to the rest of the world?  Should I repost?
-- 
 \      oo	The New Number Who,
  \____|\mm	Jeff Okamoto
  //_//\ \_\	HP Corporate Computing & Services
 /K-9/  \/_/	okamoto@ranma.corp.hp.com
/___/_____\	
-----------	(415) 857-6236