From e34b1c2adefb8c741b4cdbda5e624753ac73d041 Mon Sep 17 00:00:00 2001 From: Raphael Manfredi Date: Thu, 24 Feb 2022 11:34:48 +0100 Subject: [PATCH 1/6] gsh: let -C also copy directories remotely. Copies are done recursively and original permissions and timestamps are preserved. --- gsh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/gsh b/gsh index d2cdbba..92fe35c 100755 --- a/gsh +++ b/gsh @@ -25,7 +25,7 @@ gsh [OPTIONS] SYSTEMS CMD... -r, --run-locally Run commands locally (replaces some $var for you) -s, --show-commands Displays the command before the output report -t, --tabulate Align host output and prefixes nicely - -C, --copy DIR Copies specified files to remote DIR on each host + -C, --copy DIR Copies specified entries to remote DIR on each host -L, --force-user USER Force USER, superseding users from ghosts file -V, --version Report the version and exit -X, --extra-ssh Supply extra arguments to ssh @@ -143,15 +143,17 @@ files to the remote DIR on each host. For instance: - gsh -C /tmp all file1 file2 /path/file3 + gsh -C /tmp all file1 file2 /path/file3 /path/dir1 -would create a copy of all the specified files in the C directory -of all hosts. +would create a copy of all the specified files or directories (recursively) +in the C directory of all hosts. A report simply lists success or failure, but does not give detail about which files could not be copied remotely (insufficient permission on the remote host, I/O error, etc.). +Permissions and original timestamps are preserved by SCP if possible. + =item B<-L>, B<--force-user> USER SSH as a user USER on the remote machines, superseding any USER @@ -318,7 +320,6 @@ if ($opt_copy_to) { # We also need to validate that entries can be copied foreach my $file (@cmd) { die "$me: '$file' does not exist\n" unless -e $file; - die "$me: '$file' is a directory\n" if -d _; die "$me: '$file' is a device\n" if (-b _ || -c _); die "$me: '$file' is a pipe\n" if -p _; die "$me: '$file' is a socket\n" if -S _; @@ -439,7 +440,7 @@ foreach my $ghost (@BACKBONES) { $user = $remote_user if ($remote_user && !defined($user)); my $target = defined($user) ? "$user\@host" : $host; push(@list, "$target:$dir"); - @run = ("scp", "-o", "BatchMode=yes", @extra, @list); + @run = ("scp", "-rp", "-o", "BatchMode=yes", @extra, @list); } else { push(@extra, "-p", $port) if defined $port; push(@extra, defined($user) ? "$user@$host" : $host); From 835e1d6af3d9b638b33c15ade522255155162c27 Mon Sep 17 00:00:00 2001 From: Raphael Manfredi Date: Thu, 10 Mar 2022 09:58:32 +0100 Subject: [PATCH 2/6] Remove left-over line from refactoring. --- gsh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gsh b/gsh index 92fe35c..e973a12 100755 --- a/gsh +++ b/gsh @@ -587,10 +587,6 @@ sub report_error { } }; -warn sprintf("$me: error reported for $errored host%s\n", $errored > 1 ? "s" : "") - if $errored; - - sub show_output { my ($waiting) = @_; # This loop checks to see if there is any output waiting to be From fea7fca23b8cd25deb338e0cea6be9983e5d8d50 Mon Sep 17 00:00:00 2001 From: Raphael Manfredi Date: Thu, 10 Mar 2022 10:01:10 +0100 Subject: [PATCH 3/6] Show error in the unlikely case we cannot exec() ssh. --- gsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gsh b/gsh index e973a12..90117cd 100755 --- a/gsh +++ b/gsh @@ -450,7 +450,7 @@ foreach my $ghost (@BACKBONES) { } # should never get to next line - die "Exec of ssh to $host failed!\n"; + die "$me: exec of ssh to $host failed: $!!\n"; } elsif (!$pid) { # report failures # !$pid is true for 0 also... From 8991e97e1f1dafb746feffcc89548acbc4000bdb Mon Sep 17 00:00:00 2001 From: Raphael Manfredi Date: Thu, 10 Mar 2022 10:02:54 +0100 Subject: [PATCH 4/6] Comment typo fix. --- gsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gsh b/gsh index 90117cd..b4b6a33 100755 --- a/gsh +++ b/gsh @@ -590,7 +590,7 @@ sub report_error { sub show_output { my ($waiting) = @_; # This loop checks to see if there is any output waiting to be - # printed. Since we're going it alphabetically by machine name, + # printed. Since we're doing it alphabetically by machine name, # it will quit immediately if it comes across an "empty" output # in the alpha-sorted list of keys. # A lone "." means that a machine finished without any output. From e8a84d018c56ff5d1ce2be5e860d0ec01418d904 Mon Sep 17 00:00:00 2001 From: Raphael Manfredi Date: Thu, 10 Mar 2022 10:05:32 +0100 Subject: [PATCH 5/6] Use stderr if we have to yell... --- gsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gsh b/gsh index b4b6a33..3be9b0c 100755 --- a/gsh +++ b/gsh @@ -686,7 +686,7 @@ sub gsh_catch { } # yell if wait is lying to us if ($pid < 0) { - print "Missed a child??! May have to Ctrl-C out.\n"; + warn "$me: missed a child??! May have to Ctrl-C out.\n"; } else { grab_output($pid, $type, $status); From 44fd1e2dd4c360f30090fb510dc329438af470a2 Mon Sep 17 00:00:00 2001 From: Raphael Manfredi Date: Thu, 10 Mar 2022 10:16:16 +0100 Subject: [PATCH 6/6] gsh: warn if we get partial empty output from hosts. --- gsh | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/gsh b/gsh index 3be9b0c..ae14180 100755 --- a/gsh +++ b/gsh @@ -338,7 +338,8 @@ if ($opt_tabulate) { } # # Progress counters -my ($contacted, $replying, $skipped, $completed, $errored) = (0, 0, 0, 0, 0); +my ($contacted, $replying, $skipped, $completed, $errored, $empty) = + (0, 0, 0, 0, 0, 0); my @errored; my @skipped; my $hosts = @BACKBONES; # Number of selected hosts @@ -530,6 +531,8 @@ while (defined($togo)) { } } +sub plural ($) { $_[0], 1 == $_[0] ? "" : "s" } + # handle any other output that hadn't been printed yet show_output(0); tty_progress_clear(); @@ -537,6 +540,11 @@ tty_progress_clear(); report_error("skipped %d host%s", \@skipped); report_error("error reported for %d host%s", \@errored); +if ($empty != 0 && $empty != $replying) { + warn sprintf "$me: got empty output for %u/%u replying host%s\n", + $empty, plural($replying); +} + #print "skipped machines: $forked\n"; #@tried=split(/\s+/,$forked); # @@ -546,9 +554,7 @@ report_error("error reported for %d host%s", \@errored); exit($errored ? EXIT_ERRORED : EXIT_OK); - - -# subroutines +### subroutines # Clear previous tty progress by overwriting a blank line. sub tty_progress_clear { @@ -578,7 +584,7 @@ sub report_error { return unless @$aref; my $cnt = @$aref; my $list = join(', ', @$aref); - my $msg = "$me: " . sprintf($fmt, $cnt, $cnt > 1 ? "s" : ""); + my $msg = "$me: " . sprintf($fmt, plural($cnt)); if (length($msg) + length($list) < 77) { warn "$msg ($list)\n"; } else { @@ -661,7 +667,8 @@ sub grab_output { } # if there was no output, signal to the output printing loops if (0 == $length) { - $output{$host} = "." + $output{$host} = "."; + $empty++; } elsif ($type =~ /^interrupt/) { $output{$host} .= "\n" if "\n" ne substr($output{$host}, -1); $output{$host} .= $showlist{$host} . "(interrupted by signal)\n";