views:

8938

answers:

10

I am currently creating an overnight job that calls a Unix script which in turn creates and ftps a file. I would like to check all possible return codes. The unix man for ftp doesn't list return codes. Does anyone know where to find a list? Anyone with experience with this? We have other scripts that grep for certain return strings in the log, and they send an email when in error. However, they often miss unanticipated codes. I am then putting the reason into the log and the email.

Thanks, Glenn

A: 

Why not just store all output from the command to a log file, then check the return code from the command and, if it's not 0, send the log file in the email?

Terence Simpson
+1  A: 

lame answer I know, but how about getting the ftp sources and see for yourself

How do I go about this?
+2  A: 

The FTP command does not return anything other than zero on most implementations that I've come across.

It's much better to process the three digit codes in the log - and if you're sending a binary file, you can check that bytes sent was correct.

The three digit codes are called 'series codes' and a list can be found here

ColinYounger
Sorry to be a pain, but I have 2 questions.1) But where is the log? I assumed that it would be in $ftpreturn.2) How do I check the bytes sent?
I figured it out. Thanks for the help.Glenn.
A: 

Thanks guys, as you can probably tell, my unix scripting is not that far along. I'm basically working from other scripts by people that used to work here. However, I'd like to make it more bulletproof than what I've found so far. I appreciate all answers so far. And I'm researching to get more detail.

Basically my code so far is as follows: echo " open $ftpip pwd binary lcd /out cd /in mput $datafile quit"|ftp -iv > $ftpreturn

The -v option looks like what I need. But the $ftpreturn variable is blank. The file isn't getting ftp'd and is failing silently. What am I missing?

Thanks again, Glenn

+1  A: 

I think it is easier to run the ftp and check the exit code of ftp if something gone wrong.

I did this like the example below:

# ...
ftp -i -n $HOST 2>&1 1> $FTPLOG << EOF
quote USER $USER
quote PASS $PASSWD
cd $RFOLDER
binary
put $FOLDER/$FILE.sql.Z $FILE.sql.Z
bye
EOF

# Check the ftp util exit code (0 is ok, every else means an error occurred!)
EXITFTP=$?
if test $EXITFTP -ne 0; then echo "$D ERROR FTP" >> $LOG; exit 3; fi
if (grep "^Not connected." $FTPLOG); then echo "$D ERROR FTP CONNECT" >> $LOG; fi 
if (grep "No such file" $FTPLOG); then echo "$D ERROR FTP NO SUCH FILE" >> $LOG; fi 
if (grep "access denied" $FTPLOG ); then echo "$D ERROR FTP ACCESS DENIED" >> $LOG; fi
if (grep "^Please login" $FTPLOG ); then echo "$D ERROR FTP LOGIN" >> $LOG; fi

Edit: To catch errors I grep the output of the ftp command. But it's truly it's not the best solution.

I don't know how familier you are with a Scriptlanguage like Perl, Python or Ruby. They all have a FTP module which you can be used. This enables you to check for errors after each command. Here is a example in Perl:

#!/usr/bin/perl -w
use Net::FTP;
$ftp = Net::FTP->new("example.net") or die "Cannot connect to example.net: $@";
$ftp->login("username", "password") or die "Cannot login ", $ftp->message;
$ftp->cwd("/pub") or die "Cannot change working directory ", $ftp->message;
$ftp->binary;
$ftp->put("foo.bar") or die "Failed to upload ", $ftp->message;
$ftp->quit;
jk
From what I understand, the ftp return can't be trusted. As mentioned by Colin below.
+1  A: 

Install the ncftp package. It comes with ncftpget and ncftpput which will each attempt to upload/download a single file, and return with a descriptive error code if there is a problem. See the “Diagnostics” section of the man page.

andrew
A: 

Here is what I finally went with. Thanks for all the help. All the answers help lead me in the right direction. It may be a little overkill, checking both the result and the log, but it should cover all of the bases.

Thanks again, Glenn

echo "open ftp_ip

pwd

binary

lcd /out

cd /in

mput datafile.csv

quit"|ftp -iv > ftpreturn.log

ftpresult=$?

bytesindatafile=wc -c datafile.csv | cut -d " " -f 1

bytestransferred=grep -e '^[0-9]* bytes sent' ftpreturn.log | cut -d " " -f 1

ftptransfercomplete=grep -e '226 ' ftpreturn.log | cut -d " " -f 1

echo "-- FTP result code: $ftpresult" >> ftpreturn.log echo "-- bytes in datafile: $bytesindatafile bytes" >> ftpreturn.log echo "-- bytes transferred: $bytestransferred bytes sent" >> ftpreturn.log

if [ "$ftpresult" != "0" ] || [ "$bytestransferred" != "$bytesindatafile" ] || ["$ftptransfercomplete" != "226" ]

then

echo "-- abend FTP Error occurred" >> ftpreturn.log

mailx -s 'FTP error' cat email.lst < ftpreturn.log

else

echo "-- file sent via ftp successfully" >> ftpreturn.log

fi

A: 

You said you wanted to FTP the file there, but you didn't say whether or not regular BSD FTP client was the only way you wanted to get it there. BSD FTP doesn't give you a return code for error conditions necessitating all that parsing, but there are a whole series of other Unix programs that can be used to transfer files by FTP if you or your administrator will install them. I will give you some examples of ways to transfer a file by FTP while still catching all error conditions with little amounts of code.

FTPUSER is your ftp user login name

FTPPASS is your ftp password

FILE is the local file you want to upload without any path info (eg file1.txt, not /whatever/file1.txt or whatever/file1.txt

FTPHOST is the remote machine you want to FTP to

REMOTEDIR is an ABSOLUTE PATH to the location on the remote machine you want to upload to

Here are the examples:

curl --user $FTPUSER:$FTPPASS -T $FILE ftp://$FTPHOST/%2f$REMOTEDIR

ftp-upload --host $FTPHOST --user $FTPUSER --password $FTPPASS --as $REMOTEDIR/$FILE $FILE

tnftp -u ftp://$FTPUSER:$FTPPASS@$FTPHOST/%2f$REMOTEDIR/$FILE $FILE

wput $FILE ftp://$FTPUSER:$FTPPASS@$FTPHOST/%2f$REMOTEDIR/$FILE

All of these programs will return a nonzero exit code if anything at all goes wrong, along with text that indicates what failed. You can test for this and then do whatever you want with the output, log it, email it, etc as you wished.

Please note the following however:

  1. "%2f" is used in URLs to indicate that the following path is an absolute path on the remote machine. However, if your FTP server chroots you, you won't be able to bypass this.

  2. for the commands above that use an actual URL (ftp://etc) to the server with the user and password embedded in it, the username and password MUST be URL-encoded if it contains special characters.

  3. In some cases you can be flexible with the remote directory being absolute and local file being just the plain filename once you are familiar with the syntax of each program. You might just have to add a local directory environment variable or just hardcode everything.

  4. IF you really, absolutely MUST use regular FTP client, one way you can test for failure is by, inside your script, including first a command that PUTs the file, followed by another that does a GET of the same file returning it under a different name. After FTP exits, simply test for the existence of the downloaded file in your shell script, or even checksum it against the original to make sure it transferred correctly. Yeah that stinks, but in my opinion it is better to have code that is easy to read than do tons of parsing for every possible error condition. BSD FTP is just not all that great.

DevelopersDevelopersDevelopers
A: 

Most of the FTP clients return an exit code "0" even if there is an error occured during the FTP.

I am also Facing the problem, where in I am checking for the error codes. But I get the error code number in the bytes sent and the validation fails.

I tried like :

if [[ egrep '^202 |^421 |^426 |^450 |^500 |^501 |^503 |^530 |^550 |^553 |^666 |^777 |^999 ' test.log ]] echo " Error in FTP !!! " else echo " FTP Successful !!!" fi

Can any one help me out how to seggregate the error code from the number comes alongwith the message "byte sent" e.g "220 Bytes sent in 0.001 seconds (220 Kbytes/sec)".

A: 

Hi, I like the solution from Anurag, for the bytes transfered problem I have extended the command with grep -v "bytes"

ie

grep "^530" ftp_out2.txt | grep -v "byte"

-instead of 530 you can use all the error codes as Anurag did.

eNorm