LJRabalais has asked for the wisdom of the Perl Monks concerning the following question:

We have an application written primarily in PERL that submits JCL via the MVS::JESFTP from Linux (ASCII) for execution on MVS/TSO (EBCDIC). Recently, we were tasked with converting all FTP connections to MVS to SFTP. We have been unable to locate an SFTP version of MVS::JESFTP, and were wondering is such a module exists, or might be in development.

Replies are listed 'Best First'.
Re: Is there SFTP version of MVS::JESFTP?
by choroba (Cardinal) on Jun 28, 2024 at 17:07 UTC
    The documentation of MVS::JESFTP (see? A link!) states:

    > This module uses the Net::FTP module under the hood to handle the FTP chores.

    If you don't find a ready made tool, you might try to replace Net::FTP with something else, e.g. Net::SFTP or Net::SFTP::Foreign (I had success with the latter in the past).

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: Is there SFTP version of MVS::JESFTP?
by NERDVANA (Priest) on Jun 29, 2024 at 20:13 UTC
    With the last release of that module 21 years ago, I think it's safe to say that author isn't going to add SFTP support any time soon :-)

    If you look at the source of the module, though, there's not much there. It should be fairly easy to write a new one for SFTP.

    Unfortunately, the API between Net::FTP and Net::SFTP are not quite the same. In case it helps, here is some code I have that hides the difference between the two modules with my own API (though this only covers ls and get, not put)

    *NOTE* Actually wait, looking closer at the original code I see what looks like a custom FTP command? https://metacpan.org/dist/MVS-JESFTP/source/JESFTP.pm#L106. Are you sure that job control is possible over SFTP?

    sub _fetch_uri { my ($self, $uri)= @_; my $conn= $self->_cached_connection($uri); if ($uri->scheme eq 'ftp') { my $buf= ''; open my $fh, '>', \$buf or die; $conn->get($uri->path, $fh) or die 'file could not be downloaded: ' . $conn->message; close $fh; return $buf; } elsif ($uri->scheme eq 'sftp') { return scalar $conn->get($uri->path); } elsif ($uri->scheme eq 'file') { return $conn->slurp_raw; } else { die "BUG: Unhandled scheme ".$uri->scheme; } } # Return arrayref of file names under the URI path # sub _readdir_uri { my ($self, $uri)= @_; my $conn= $self->_cached_connection($uri); if ($uri->scheme eq 'ftp') { # connection refers to root filesystem. path can be multiple co +mponents # deep reaching into the file tree. Then, need to remove all di +rectory portions # of the response. return [ map { $_ =~ s|.*/||; $_ } $conn->ls($uri->path) ]; } elsif ($uri->scheme eq 'sftp') { return [ map $_->{filename}, $conn->ls($uri->path) ]; } elsif ($uri->scheme eq 'file') { return [ $conn->children ]; } else { die "BUG: Unhandled scheme ".$uri->scheme; } } sub _cached_connection { my ($self, $uri)= @_; if ($uri->scheme eq 'ftp') { return ($self->_conn_cache->{'ftp:'.$uri->user.'@'.$uri->host} / +/= $self->_connect_ftp($uri)); } elsif ($uri->scheme eq 'sftp') { return ($self->_conn_cache->{'sftp:'.$uri->user.'@'.$uri->host} +//= $self->_connect_sftp($uri)); } elsif ($uri->scheme eq 'file') { _logcroak('Refusing to access local file URL') unless $ENV{DATA_SERVICE_ACCESS_LOCAL}; # for debugging return Path::Tiny::path($uri->file); } else { _logcroak("Don't know how to access ".$self->_redacted_uri($uri) +); } } sub _connect_ftp { my ($self, $uri)= @_; my $host= $uri->host; my $ftp = Net::FTP->new($host, Passive => 1) or die "Cannot connect to '$host': $@"; $ftp->login($uri->user, $uri->password) or die 'Cannot login: ', $ftp->message; $ftp->binary or die "Can't start binary mode"; return $ftp } sub _connect_sftp { my ($self, $uri)= @_; my $host= $uri->host; Net::SFTP->new( $host, user => $uri->user, password => $uri->password, ssh_args => [ # See https://stackoverflow.com/questions/41964908/netsftp-pe +rl-rsa-authentification/51863332#51863332 identity_files => [], # deprecated, but needed for ancient servers options => [ "MACs +hmac-sha1" ], ], ); }