#!/usr/bin/perl -w
#
# rcmd.pl
#
# run a command on multiple hosts!
# reads hosts from ~/rhosts
#
# if ~/rhosts is
# host group1,group3
# host2 group2,group3
# host3 group2
# then
# rcmd.pl -g group2 ls
# will run ls on host2 and host3
#
# great for run this command on "print hosts" or "solaris 8" machines
+or
# red hat machines etc.
#
# Requires ssh installed- yeah I could have used Net:SSH,
# not sure if that would any value though :)
#
# rcmd.pl started out as a quick and dirty one off
# shell script and has grown...
#
use strict;
use Sys::Hostname;
use Getopt::Std;
my $home=get_home();
my %settings = (
domain => 'some.net.au',
DEBUG => 0,
SSH => "/usr/local/bin/ssh",
SCP => "/usr/local/bin/scp",
HOST_FILE => "$home/rhosts",
runlocally => 0,
);
main_loop();
exit;
sub main_loop {
my %args;
getopts("g:hlnz", \%args); # see print_help() for a description of
+options
print_help() and exit if $args{h};
print_help() and exit if ! $args{g};
my $host_group = $args{g} || '';
my $no_prompt = 1 if $args{n};
my $no_errors = 1 if $args{z};
$settings{runlocally} = 1 if $args{l};
print_help() and die "Specify command to run!\n" if ( ! scalar @ARGV
+);
# the shell expands ~ and $home might be someplace different
# on the destination host...
my @command = map { s/^$home/~/; $_ } @ARGV;
unshift @command, $settings{SSH};
push @command, " 2>/dev/null" if $no_errors;
my @dest_hosts=get_hosts($settings{HOST_FILE}, $host_group);
for my $host (@dest_hosts){
unless ( $no_prompt ){
print "Run @ARGV on $host [y/n]: ";
chomp (my $answer = <STDIN>);
next if ( $answer !~ /^y/i );
}
my @cmd = @command;
splice(@cmd, 1, 0, $host); # insert the hostname
if ( $settings{runlocally} and $host eq $settings{localhost}){
shift @cmd; shift @cmd; # remove ssh and $hostname
}
print "Running [@cmd]\n" if $settings{DEBUG};
my @result = `@cmd`;
print "$host: ", @result, "\n";
}
}
sub get_hosts {
my $hosts_file = shift || die "sub get_hosts did not get a required
+argument\n";
my $host_group = shift || die "sub get_hosts did not get a required
+argument\n";
my $localhost = hostname();
$localhost = (gethostbyname("$localhost.$settings{domain}"))[0] || $
+localhost;
print "localhost: [$localhost]\n" if $settings{DEBUG};
$settings{localhost} = $localhost;
my @hosts;
open (HOSTS, $hosts_file) || die "Could not open $hosts_file : $!\n"
+;
while (<HOSTS>){
next if /^\s*$/;
next if /^\s*#/;
chomp;
my ($host, $groups) = split /\s+/;
$host .= ".$settings{domain}" if ($host !~ /\./);
my %groups = map { $_, 1 } split /,/, $groups;
next if ( $host eq $localhost and ! $settings{runlocally});
next if ( ! $groups{$host_group} and $host_group ne "all");
print "Selecting [$host]\n" if $settings{DEBUG};
push @hosts, $host;
}
close(HOSTS);
return @hosts;
}
sub get_home {
my @pwd = getpwuid($<);
my $home = $ENV{HOME} || $ENV{LOGDIR} || $pwd[7]
or die "Could not determine home directory for $<";
return $home;
}
sub print_help {
print "rput.pl -g <group> [options] file\n\n",
"\twhere <group> is a group in your ~/rhosts file or \"all\"\n",
"\t-h print this message\n",
"\t-l run on local host\n",
"\t-n no prompt just do it!\n",
"\t-z suppres error messages\n";
}
|