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

Dear wise ones-

I have a script whose purpose is to secure-copy a file to a remote host. I'm using the Net::SCP::Expect module (which ultimately calls Expect.pm itself) to perform the 'scp' command.

This script is intended to be run from cron (and another third-party job management package, Autosys, we use here in shop).

Anyhow, the problem is apparent in both cron and Autosys. When run from the command line, the script runs fine. It secure copies the file from the local host to the remote one correctly. The problem arises when I attempt to run the same script (as the same user) from cron.

Below is the Expect::spawn code.

Expect forks to run the 'scp' command and when run from the command line the following fork call returns a value greater than zero, when run via cron the fork call returns a zero value and execution stops on the subsequent 'close(STDOUT)' call within the Expect.pm::spawn() subroutine.

I noted below where it stops:

sub spawn { ... ... my $pid = fork; unless (defined ($pid)) { warn "Cannot fork: $!" if $^W; return undef; } if($pid) { # parent my $errno; ${*$self}{exp_Pid} = $pid; close STAT_WTR; $self->close_slave(); $self->set_raw() if $self->raw_pty and isatty($self); # now wait for child exec (eof due to close-on-exit) # or exec error my $errstatus = sysread(STAT_RDR, $errno, 256); die "Cannot sync with child: $!" if not defined $errstatus; close STAT_RDR; if ($errstatus) { $! = $errno+0; warn "Cannot exec(@cmd): $!\n" if $^W; return undef; } } else { # child close STAT_RDR; $self->make_slave_controlling_terminal(); my $slv = $self->slave() or die "Cannot get slave: $!"; $slv->set_raw() if $self->raw_pty; close($self); close(STDIN); open(STDIN,"<&". $slv->fileno()) or die "Couldn't reopen STDIN for reading, $!\n"; # # ---- execution stops/waits on the call below ---- # close(STDOUT); open(STDOUT,">&". $slv->fileno()) or die "Couldn't reopen STDOUT for writing, $!\n"; close(STDERR); open(STDERR,">&". $slv->fileno()) or die "Couldn't reopen STDERR for writing, $!\n"; { exec(@cmd) }; print STAT_WTR $!+0; die "Cannot exec(@cmd): $!\n"; } }

I have tried numerous alternative methods of execution, ranging from having cron call a 'driver' script that does a system() call to execute this script, to autoflushing STDOUT prior to calling new() for Expect, to scouring the NET::SCP::Expect and Expect dcoumentation to see if I'm missing something. Regardless, execution still hangs on that 'close(STDOUT)' call in spawn. It seems that it's blocking on the close, waiting for someone to relinquish the filehandle, I just don't know who. :)

Any help/hints/ideas would be greatly appreciated.

- Camper

Replies are listed 'Best First'.
Re: Issues using Expect.pm from cronjob
by Fletch (Bishop) on Mar 16, 2006 at 15:03 UTC

    You might try something like:

    • Add code to write the parent process ID to a file somewhere and then sleep (say) 30 seconds
    • That sleep will give you enough time to start up strace (or ktrace, or whatever your OS' equivalent is) on the parent process with following forks enabled

    That might help you isolate more what might be blocking or more specifically where it's blocking.

Re: Issues using Expect.pm from cronjob
by Melly (Chaplain) on Mar 16, 2006 at 15:57 UTC

    I really don't know what I'm talking about here, but what happens if you use a 'normal' file-handle rather than STDOUT? (and STDIN for that matter)

    STDOUT seems a bad choice for a cronjob - maybe cron on your system is automatically disabling it or something?

    Tom Melly, tom@tomandlu.co.uk