# Up2us -- RPM package manager manager for linux and beyond
# THIS MODULE: External program execution.
# $Id: execute.pm,v 1.3 2003/04/03 22:40:47 tomj Exp $

# Copyright Tom Jennings 2002-2003
# tomj@wps.com, http://wps.com
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the Free
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
# MA 02111-1307, USA.

# OVERVIEW:

# Executes programs for which we have configuration. Basically,
# it builds configuration for the indicated repository and invoke
# the program after building a command line. Checks for errors and
# all that rot.
#
# SOFTWARE STRUCTURE: these routines contain no interface-related
# anything. They mostly return text string error messages which can
# be displayed as the caller sees fit.


# Error messages and such.

my $cfgerr= "Config item \"%s-path\" must be an absolute pathname.";
my $forkU= "Some weird fork error what gone and killted us.";
my $forkerr= "The \"%s-path\" program exited with code %d.\n\n(Whole enchilada was \"%s\").";
my $forkoop= "The impossible has happened: fork() returned?";


#############################################################
#
# $error= &run_prog ("programname", "repositoryname", @ARGS);
#
# Executes the specified program, after building config files that
# refer to the given repository. Config items named programname-*
# should exist in up2us's config (some are mandatory, some not).
# The list of args is optional; not all programs use them, but if
# present they replace the macro names in config item "prog-args"
# named $1..$9, eg. filenames and such.

sub run_prog {
my $prog= shift;	# logical name of program,
my $rep= shift;		# repository name,
my @args= @_;		# optional args

	&build_config_for ($rep);			# make config files,
	my $e= &write_config_data;			# flush files to disk,
	return $e if $e ne $OK;

# The path to the program is mandatory, and it must begin with /
# and contain at least one other /. 

	my $pathname= &cfg_item ("$prog-path");		# prog to execute,
	return sprintf ($cfgerr, $prog) if $pathname !~ m"^/.*/";

# Build a command line, first doing any macro substitutions.

	my $a= &cfg_item ("$prog-args");		# program args,
	$a= "" if not defined $a;			# (eg. up2date)
	for (my $i= 1; scalar @args; ++$i) {		# substitute all/any,
		$_= shift @args;
		$a =~ s/\$$i/$_/g;			# make substitution,
	}
	@args= split (' ', $a);				# turn into a list,

# Now run what we brung.

	$p= "$pathname " . join (' ', @args);		# the whole thing,
	my $pid= fork();				# split 'twain,
	return $forkU if not defined $pid;		# something wrong

	if ($pid != 0) {				# yo, it's us,
		while ((my $foo= waitpid ($pid, &WNOHANG())) == 0) {
			&while_idle();			# update interface
		}
		if ($? != 0) {
			$? &= 0xffff;
			my $exit= $? >> 8;		# I took the trouble
			my $sig= $? & 127;		# to look it up,
			my $core= $? & 128;		# someday useful?
			return sprintf ($forkerr, $prog, $exit, $p);

		} else {				# success,
			return $OK;
		}

	} else {					# we're the child,
		&logorrhea ("Executing $p\n");
		exec ($pathname, @args);		# go run program,
	}
	return $forkoop;
}


	return 1;
