r4324 added RHEL6
[racktables] / gateways / deviceconfig / nc.pl
CommitLineData
3b3ea468
AA
1#!/usr/bin/perl -w
2use strict;
3use Getopt::Long qw(:config pass_through);;
4use Fcntl;
5use IPC::Open2;
6my $NC_EXEC = 'nc';
7
8my ($marker, $marker_halt);
9my $wait_for;
10my $help;
11GetOptions ("stopwhen=s" => \$marker,
12 "haltwhen=s" => \$marker_halt,
13 "putwhen=s" => \$wait_for,
14 "help|h" => \$help);
15if ($help) {
16 print <<END;
17Wrapper around nc for non-interactive sessions.
18It can close session when it sees the regexp-matching string in session output.
19It can wait for command prompt to push the next command to remote side.
20It DOES NOT directly link its standard input with nc`s standard input.
21
22Additional options availivle:
23--help, -h This help message
24--stopwhen=<regexp> Close nc when this string is seen in the output
25--putwhen=<regexp> Put next line only if last output line complies to regexp
26
27Original nc options:
28END
29 exec($NC_EXEC);
30 exit;
31}
32
33my $hostname = 'unknown';
34if (@ARGV >= 2) {
35 $hostname = $ARGV[$#ARGV - 1];
36}
37my ($break_re, $prompt_re, $halt_re);
38if ($marker) {
39 $break_re = qr/($marker)/m;
40}
41if ($marker_halt) {
42 $halt_re = qr/($marker_halt)/m;
43}
44if ($wait_for) {
45 $prompt_re = qr/$wait_for/;
46}
47$| = 1;
48
49my @cmds = <STDIN>;
50
51my $log = '';
52local (*Reader, *Writer);
53my $pid = open2(\*Reader, \*Writer, $NC_EXEC, @ARGV) or die "cant start $NC_EXEC: $!\n";
54my $stdin_ended = 0;
55
56my $total_read = 0;
57my $vec = '';
58while () {
59 vec($vec, fileno(Reader), 1) = 1;
60 select($vec, undef, undef, undef);
61
62 my $buff;
63 my $nb = sysread(Reader, $buff, 64 * 1024);
64 $total_read += $nb;
65 print $buff if $nb; # echo to STDOUT
66 if (! $nb) {
67 if (@cmds and $total_read) {
68 print STDERR "$hostname: connection interrupted by remote side.\n";
69 }
70 last; # exit if nc closed connection
71 }
72
73 $log .= $buff;
74 my $halt_matched = $halt_re && $log =~ $halt_re;
75 if ($halt_matched or $break_re && $log =~ $break_re) {
76 if ($halt_matched) {
77 chomp $log;
78 $log =~ s/.*\n//;
79 $log =~ s/[^ -~]//g;
80 print STDERR "$hostname: Matched line '$log', connection interrupted.\n";
81 exit 1;
82 }
83 else {
84 exit 0;
85 }
86 }
87 $log =~ s/.*\n//s; # keep only last line in log
88
89 if ($prompt_re and $log =~ $prompt_re) { # if interative mode and pending commands
90 if (@cmds) {
91 print Writer shift @cmds; # push one command
92 $log = '';
93 }
94 else { # if interactive mode and no more commands, exit
95 last;
96 }
97 }
98 elsif (! $prompt_re and @cmds) { # if non-interactive mode and pending commands, push them all
99 print Writer @cmds;
100 undef @cmds;
101 }
102}
103close Reader;
104close Writer;
105waitpid( $pid, 0 );
106exit $? >> 8;