package FugueConfig; use Sys::Hostname; use IO::Handle; use strict; my $rsh = $ENV{"RSH"}; $rsh = "rsh" unless defined $rsh; # apply cpp to a fugue config file and open resulting pipe sub open { my $file = shift; my @cppopts = @_; if (system("which cpp > /dev/null")) { print "cpp command can't be located\n"; return undef; } elsif (not -f $file) { print "No such file '$file'\n"; return undef; } elsif (not -r $file) { print "'$file' is unreadable\n"; return undef; } my $cpp_options = join(' ', @cppopts); open (FD, "$file") or return undef; while() { chomp; if (/^#cpp_options\s*:\s*(.*)/) { $cpp_options = $1; last; } } close(FD); print "in ivylaunch, cpp options are [$cpp_options]\n"; my $cppcmd = "cpp $file $cpp_options"; open (FD, "$cppcmd |") or return undef; return \*FD; } # end open # basic parsing of a cpped fugue config file; each element of the returned # array describes a non-empty line, according to the following format : # # [type, host, agent_name, command, [command_options]] # # where 'type' can take one of the following values 'comment', 'global', # local', 'begin', and 'end'. # a 'comment' type will be followed by an single field # sub parse { my $fd = &FugueConfig::open(@_); return undef unless $fd; my @data; my %appname; my $line = 0; while(<$fd>) { $line++; # empty lines if (/^\s*$/) { next; # comments } elsif (/^\s*\#.*$/) { push(@data, ['comment', $_]); } else { my ($type, $host, $name, $command, $param) = m/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)\#*.*$/ ; #print "### t=$type h=$host n=$name c=$command p=$param\n"; if (not defined $type) { warn ("[FugueConfig][WARNING][line $line] syntax error : ". "\n\t=> $_\n"); next; } unless ($type eq 'global' or $type eq 'local' or $type eq 'begin' or $type eq 'end') { warn ("[FugueConfig][WARNING][line $line] unknown command type ". "'$type'\n"); next; } if ($appname{$name}) { warn ("[FugueConfig][WARNING][line $line] at least 2 agents have ". "the same name '$name'; skipping all but the first\n"); next; } $appname{$name} = 1 if $type eq 'global' or $type eq 'local'; push(@data, [$type, $host, $name, $command, $param]); } } close(1, $fd); return @data; } # end parse # launch an named ivy agent on a given host and on a given ivy bus # return its pid. sub launchAgent { my ($appname, $host, $command, $options, $bus) = @_; $options .= " -b $bus" if $bus; my $command_opt = $command; $command_opt .= ' '.$options unless $options =~ /^\s*$/; &_launch($appname, $host, $command_opt, 'agent'); } # end launchAgent sub execAgentBackground { my ($appname, $host, $command, $options, $bus) = @_; $options .= " -b $bus" if $bus; my $command_opt = $command; $command_opt .= ' '.$options unless $options =~ /^\s*$/; $command_opt = "$rsh -n $host '$command_opt'" unless $host eq 'localhost' or $host eq hostname(); system("($command_opt 2>&1)&"); } # end execAgentBackground # launch a given command (not an ivy agent) on a given host sub launchCommand { my ($type, $host, $command, $options) = @_; my $command_opt = $command; $command_opt .= ' '.$options unless $options =~ /^\s*$/; &_launch($type, $host, $command_opt, 'command'); } # end launchCommand sub _launch { my ($label, $host, $command_opt, $type) = @_; my $pid = fork; warn ("[FugueConfig][WARNING] Could not fork $type \'$command_opt\'!\n"), return unless defined $pid; # parent P1 if ($pid) { print "[FugueConfig][INFO] launch on $host $label $type \'$command_opt\' ". "(pid=$pid)\n"; return ($pid); # child P2 } else { # overload parent trap $SIG{INT} = 'DEFAULT'; # remote command $command_opt = "$rsh -n $host '$command_opt'" unless $host eq 'localhost' or $host eq hostname(); pipe(READER, WRITER); WRITER->autoflush(1); my $pid2 = fork; warn ("[FugueConfig][WARNING] Could not fork $type \'$command_opt\'!\n"), return unless defined $pid2; # parent P2 if ($pid2) { close READER; CORE::open(STDOUT, ">&=WRITER") or die "[FugueConfig][WARNING] Couldn't redirect STDOUT"; exec "$command_opt 2>&1 " or die "[FugueConfig][WARNING] Couldn't launch $command_opt"; # child P3 } else { close WRITER; while() { chomp(); print "$label $_\n"; } close READER; exit; } } } # end _launch 1;