package FugueConfig; use Sys::Hostname; 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; 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; } open (FD, "cpp -traditional $file |") 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 $file = shift; my $fd = &FugueConfig::open($file); 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=".join(' ', @param)."\n"; if (not defined $type) { warn ("*** FugueConfig::parse WARNING : ". "syntax error at line $line : \n\t=> $_\n"); next; } unless ($type eq 'global' or $type eq 'local' or $type eq 'begin' or $type eq 'end') { warn ("*** FugueConfig::parse WARNING : ". "unknown command type '$type' at line $line. Ignored.\n"); next; } if ($appname{$name}) { warn ("*** FugueConfig::parse WARNING : ". "at 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) = @_; my @options = @$options if ref($options) eq 'ARRAY'; push(@options, -b => $bus) if $bus; my $command_opt = $command.' '.join(' ', @options); my $pid = fork; warn ("*** FugueConfig::launchAgent WARNING: Could not fork!\n"), return unless defined $pid; if ($pid) { # parent print "*** FugueConfig::launchAgent INFO: $host: launching $appname agent ". "with \'$command_opt\' (pid=$pid)\n"; return ($pid); } else { # child my $awk_command = "awk -W interactive '{print \"$appname  \", \$0;}'"; if ($host eq 'localhost' or $host eq hostname() ) { exec "$command_opt 2>&1 | $awk_command" or warn "*** FugueConfig::launchAgent WARNING: Error executing $command\n"; } else { exec "$rsh -n $host '$command_opt' 2>&1 | $awk_command " or warn "*** FugueConfig::launchAgent WARNING: Error executing ". "$command on $host\n"; } } } # end launchAgent # launch a given command (not an ivy agent) on a given host sub launchCommand { my ($type, $host, $command, $options) = @_; my @options = @$options if ref($options) eq 'ARRAY'; my $command_opt = $command.' '.join(' ', @options); print "*** FugueConfig::launchCommand INFO: $host: launching command ". "\'$command_opt\'\n"; my $awk_command = "awk -W interactive '{print \"$type  \", \$0;}'"; if ($host eq 'localhost' or $host eq hostname() ) { $command = "$command_opt | $awk_command "; } else { $command = "$rsh $host '$command_opt' | $awk_command "; } # print "$HEADER launching command $command\n"; system ($command); } # end launchCommand 1