-
Notifications
You must be signed in to change notification settings - Fork 0
/
urssh
executable file
·249 lines (177 loc) · 6.31 KB
/
urssh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use 5.014;
use Getopt::Long;
use Pod::Usage;
use IO::Compress::Gzip qw(gzip $GzipError);
use Archive::Tar;
use Net::OpenSSH;
# config for bash
sub ubash {
my $ursshhome = shift;
return <<EOF
#!/usr/bin/env bash
exec bash --rcfile <(echo '
if [ -e /etc/bash.bashrc ]; then . /etc/bash.bashrc; fi
if [ -e ~/.bashrc ]; then . ~/.bashrc; fi
if [ -e '$$ursshhome'/.ursshrc.d/urbashrc ]; then . '$$ursshhome'/.ursshrc.d/urbashrc; fi
export PATH=\$PATH:'$$ursshhome'
') "\$@"
EOF
}
# setup for a local config dir in the $HOME for the current user
sub setup {
my $ursshrc_d = shift;
if(-d $$ursshrc_d) {
if(-e "$$ursshrc_d/urbashrc") {
say "$$ursshrc_d and $$ursshrc_d/urbashrc were already created.";
return 1;
} else {
open(my $fh, ">$$ursshrc_d/urbashrc") || die "Can't create a urbashrc config file: $!";
say $fh "# Automaticaly generated file, you can set up your bash here";
close $fh;
say "Done.";
return 1;
}
} else {
say "Initial setup..";
say "Creating $$ursshrc_d and $$ursshrc_d/urbashrc..";
mkdir $$ursshrc_d || die "Can't create a $$ursshrc_d folder: $!";
setup($ursshrc_d);
}
}
# recursive directory traverser, return the full file list as ref to an array
sub dir_traverse {
my $dir = shift;
my @collector;
opendir(my $dh, $$dir) || die "Can't open the directory $$dir: $!";
my @curr_dir_content = grep { $_ ne '.' && $_ ne '..' } readdir($dh);
closedir $dh;
foreach my $file (@curr_dir_content) {
my $path = "$$dir/$file";
if (-d $path) {
push @collector, $_ for @{dir_traverse(\$path)};
} else {
push @collector, $path if -f $path;
}
}
return \@collector;
}
sub main {
my ($ursshrc_d, $connect_info, $cmd) = @_;
my $ssh = Net::OpenSSH->new(
$connect_info,
timeout => 10,
async => 1,
forward_X11 => 1
);
$ssh->error && die "Can't open a connection: $!";
if($cmd) {
$ssh->system($cmd);
exit(0);
}
# prepare a tmp home directory
my $ursshhome = $ssh->capture({ timeout => 10 }, "mktemp -t -d .urssh.XXXXXXXX");
$ssh->error && die "Can't create a tmp home: $!";
chomp $ursshhome;
# creating in-memory archive to keep all the files from .ursshrc.d/ directory
my $tar = Archive::Tar->new;
foreach my $file (@{dir_traverse($ursshrc_d)}) {
open(my $fh, $file);
$tar->add_data($1, do {local $/; <$fh>}) if $file =~ /(\.ursshrc\.d\/.+)$/;
close $fh;
}
my $input = $tar->write();
my $gzip_buffer;
gzip \$input => \$gzip_buffer || die "Failied to created a gzip: $GzipError";
$ssh->system({stdin_data => $gzip_buffer}, "tar xmz -C $ursshhome/");
$ssh->system({stdin_data => ubash(\$ursshhome)}, "cat > '$ursshhome/urbash'");
$ssh->system("chmod +x '$ursshhome/urbash'");
# login
$ssh->system({tty => 1, forward_X11 => 1}, qq{export URSSH_HOME="$ursshhome" && export URSSHRC_D="\$URSSH_HOME/.ursshrc.d" && '$ursshhome/urbash'});
# cleanup
$ssh->system("rm -rf '$ursshhome'");
}
#config section
my $ursshrc_d = "$ENV{HOME}/.ursshrc.d";
# help section
my $help = 0;
my $man = 0;
my $setup = 0;
GetOptions('help|?' => \$help, man => \$man, 'setup' => \$setup);
pod2usage(1) if $help;
pod2usage(-verbose => 2) if $man;
setup(\$ursshrc_d) && exit(0) if $setup;
pod2usage("$0: No connection string was given") if @ARGV == 0;
setup(\$ursshrc_d) unless -f "$ursshrc_d/urbashrc";
main(\$ursshrc_d, @ARGV);
__END__
=pod
=head1 NAME
urSSH - Your SSH Client
=head1 SYNOPSIS
urssh [options] B<[user:[password@]]host[:port] ['command']>
Options:
--help brief help message
--man full documention page
--setup create a folder structure
=head1 OPTIONS
=over 8
=item B<--help>
Print a brief help message and exits
=item B<--man>
Print the manual page with full description
=item B<--setup>
Create a folder structure in the B<$HOME> of current user and exit.
B<$HOME/.ursshrc.d> and B<$HOME/.urbashrc.d/urbashrc> will be created.
=back
=head1 DESCRIPTION
This simple script gives a possibility to connect over SSH to remote host and to take all your
config files with you. It depends on only one perl package B<Net::OpenSSH>, which should be installed.
All you need to do is to place all the configs and other files you want to take with you
over ssh to B<$HOME/.ursshrc.d> and then edit config file for for modified bash B<$HOME/.urbashrc.d/urbashrc>
in order to use those configs and files. You should remember the more things (the bigger they will be), the
longer you will need to wait until connection will get opened:
C<echo 'PGHOST=10.10.10.1' E<gt>E<gt> $HOME/.ursshrc.d/urbashrc>
C<urssh 10.10.10.2>
In the config files you can use next variables:
- B<$URSSHRC_D> - which points to B<.urbashrc.d> of temporary home (see below) on the remote host
- B<$URSSH_HOME> - which points to temporary home on the remote host
Example:
Let's say you want to create a custom environment for a specific host, so we can create next folder/files structure:
$HOME/.ursshrc.d/
\
\_urbashrc
|_server1rc
|_screenrc
with next content:
B<urbashrc>
# reading exteranl config file for Server1
source $URSSHRC_D/server1rc
B<server1rc>
# here can be some useful information
if [ -e /etc/motd ]; then cat /etc/motd; fi
# extend the $PATH variable
export PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin
# get rid of all aliases set up before
unalias -a
# set up my own aliases
alias ls="ls --color=auto"
alias grep="grep --color=auto"
alias egrep="egrep --color=auto"
alias screen="screen -c $URSSHRC_D/screenrc -s $URSSH_HOME/urbash"
and B<screenrc> file is a regular config for GNU Screen
After connection the environment will be set up reding all this files.
There is a possibility to specify login and password with hostname/IP in the connection string. In order
to support this the perl package B<IO::Pty> should be installed. Then one can use next connection string:
C<urssh user:p@[email protected]>
The script supports running single commands as well:
C<urssh 10.10.10.2 'ls -la'>
which will list your home directory
=head1 AUTHOR
Oleksandr Kylymnychenko, [email protected]
=head1 COPYRIGHT AND LICENSE
GNU GPL, Version 2
=cut