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

solved see my reply to original post

Greetings monks,

I have a problem with Net::FTP and I'm not sure if it's a bug/feature of the module or just my incompetence in Perl :)

Below is a code snippet. What I'm trying to accomplish is to catch *any* failure during the FTP transaction. I thought what I coded up would work, but on two occasions now, this section of code has failed to catch the error(s).
if (($ftp->login($data->{'login'}, $data->{'pw'}) or $log->logwarn("upload_file: xqe $data->{'id'}, ", $ftp->message)) && ($ftp->binary or $log->logwarn("upload_file: xqe $data->{'id'}, ", $ftp->message)) && ($ftp->cwd($data->{'remote_dir'}) or $log->logwarn("upload_file: xqe $data->{'id'}, ", $ftp->message)) && ($ftp->put($to_upload) or $log->logwarn("upload_file: xqe $data->{'id'}, ", $ftp->message)) && ($ftp->quit)) { return 1; } else { $log->error("upload_file: xqe $data->{'id'}, " . "upload failed for $to_upload"); return undef; }

The two errors that this has failed to catch are 1) a 552 where my disk quota was exceeded which cause an abort and 2) a 550 where i tried to CWD to a directory that didn't exist.

I though surely that the ABORT caused by the 552 would have caused an error, but I was mistaken.

so, what am I doing wrong?

forever in everyone's debt,
ryanc

Replies are listed 'Best First'.
Re: Net::FTP not catching errors, my fault?
by tphyahoo (Vicar) on Jun 06, 2005 at 14:54 UTC
    Ryanc, I can't tell you exactly what your problem is but I am guessing your logic is choking here with too many ands and ors. I tidied things up a bit below and my brain swims trying to understand exactly what is being anded and ored in various places. Try getting this cleaner and I bet it will start working.

    net::ftp is probably catching the error just fine, but some other combination of your logic is returning true. Remember, FALSE or TRUE or FALSE is... true.

    if ( ( $ftp->login($data->{'login'}, $data->{'pw'}) or $log->logwarn("upload_file: xqe $data->{'id'}, ", $ftp->mess +age) ) && ($ftp->binary or $log->logwarn("upload_file: xqe $data->{'id'} +, ", $ftp->message)) && ($ftp->cwd($data->{'remote_dir'}) or $log->logwarn("upload_file: xqe $data->{'id'}, ", $ftp->message)) && ($ftp->put($to_upload) or $log->logwarn("upload_file: xqe $data->{'id'}, ", $ftp->message)) && ($ftp->quit) ) { return 1; } else { $log->error("upload_file: xqe $data->{'id'}, " . "upload failed for $to_upload"); return undef; }
      thanks for your reply.

      what I'm trying to do is to accomplish 5 steps and if any of them fail, fail the whole thing. in addition, when one of those five steps fails, log it...which should work because according to the Net::FTP documentation you can do the following:
          $ftp->binary or die "$ftp->message\n";
      I'm trying to change that to:
          $ftp->binary or $log->logwarn("text", $ftp->message);

      Here's the pseudo-code for what I want my end result to be:
      if (login OR log error) AND (switch to binary mode OR log error) AND (change current diretory OR log error) AND (get/put file OR log error) AND (quit OR log error) return success else return failure

      thanks,
      ryanc
        The pseudo-code is exactly what tphyahoo was pointing you at. Consider this:
        #!/usr/bin/perl use strict; use warnings; sub fails { 0 } sub logs { print "error!\n"; 1 } (fails or logs) and print "all ok so far...\n"; __END__ ~/sviluppo/perl> perl example.pl error! all ok so far...
        As you can see, you have to beware of the return value for your log function, otherwise it will happily turn an error into something good. You could use some exception handling here:
        #!/usr/bin/perl use strict; use warnings; sub fails { 0 } sub logs { print "error: @_"; 1 } eval { 1 or die "some message here for first part"; fails or die "some message here for second part"; }; if ($@) { logs($@); exit 1; # i.e. return failure } # Otherwise all ok... __END__ ~/sviluppo/perl> perl example.pl error: some message here for second part at example.pl line 11.

        Flavio (perl -e 'print(scalar(reverse("\nti.xittelop\@oivalf")))')

        Don't fool yourself.
        Dumb question ... what's your logwarn returning? If it returns a true value you continue on to the next condition ...
        if ( change current dir OR log error ) AND ... if ( 0 OR 1 ) AND ... if( 1 ) AND ...

        Personally, I would wrap the code up in an eval:

        eval { $ftp->login($data->{'login'}, $data->{'pw'}) or die($ftp->message); $ftp->binary or die($ftp->message); $ftp->cwd($data->{'remote_dir'}) or die($ftp->message); $ftp->put($to_upload) or die($ftp->message); $ftp->quit; }; if( $@ ) { $log->error("upload_file: xqe $data->{'id'}, " . $@); return undef; } else { return 1; }
        -derby
        As has been pointed out, if logwarn returns true, then all the ftp commands are going to be run regardless (as each condition checked by the and's are going to be true).

        As you print the same log info each time, you could try something like the following, which avoids the constant line-noise log writing.

        if ($ftp->login($data->{'login'}, $data->{'pw'}) and $ftp->binary and $ftp->cwd($data->{'remote_dir'}) and $ftp->put($to_upload) and $ftp->quit) { return 1; } else { $log->logwarn("upload_file: xqe $data->{'id'}, ", $ftp->message) $log->error("upload_file: xqe $data->{'id'}, " . "upload failed fo +r $to_upload"); return undef; }
        ---
        my name's not Keith, and I'm not reasonable.
      using an eval worked marvelously. here is my resulting code:
      eval { $ftp->login($data->{'login'}, $data->{'pw'}) or die $ftp->mess +age; $ftp->binary or die $ftp->mess +age; $ftp->cwd($data->{'remote_dir'}) or die $ftp->mess +age; $ftp->put($to_upload) or die $ftp->mess +age; $ftp->quit or die $ftp->mess +age; }; if ($@) { $log->logwarn("upload_file: xqe $data->{'id'}, " . $@); $log->error("upload_file: xqe $data->{'id'}, " . "PUT $to_upload failed"); return undef; } else { return 1; }

      thanks all.
      ryanc
Re: Net::FTP not catching errors, my fault?
by cool_jr256 (Acolyte) on Jun 06, 2005 at 15:48 UTC
    Correct me if i'm wrong...but I think the logic is wrong...but than again I'm spaced out today..
    Try to break up your if statements(much easier to debug..) or use 'eval' as suggested in previous note..
      yup, just a few moments ago I came to the same realization after placing my logic up on a big white board. I stepped back and realized that if (this or that) will usually return true and my if() will continue. so, I'll try the eval and report back.

      thanks all,
      ryanc