# SccsId[] = "%W% (USL function) %G%"
FTPH_name="FTP_HOST"
if [ ".${SECONDS}" = "." ]; then # Bourne function already loaded?
[ ."`set|egrep '^$FTPH_name\(\)\{$'`" != . ] && FTPH_loaded=1
else # Korn or Bash shell and function already loaded?
if [ `expr "\`uname -s\`" : "[Ll][Ii][Nn][Uu][Xx]"` -eq 0 ]; then
[ ."`typeset +f|awk '/^'$FTPH_name'[=\(]?/'`" != . ] && FTPH_loaded=1
else # Linux
[ ."`typeset -F|awk '/^'$FTPH_name'[=\(]?/'`" != . ] && FTPH_loaded=1
fi
fi
if [ 0${FTPH_loaded} -eq 0 ]; then
#----------------------------------------------------------------------#
FTP_HOST() # Function documentation located at bottom. #
# $1 = host, $2-$n remaining ftp commands #
#----------------------------------------------------------------------#
{
OZ=`uname -s 2> /dev/null|tr '[A-Z]' '[a-z]' 2> /dev/null`
if [ ."$OZ" != ."linux" ]; then
AWK="nawk"
KILL="/bin/kill"
else # Linux
AWK="gawk"
KILL="kill"
fi
if [ .${SHLIB} = . ]; then SHLIB=/usr/local/scripts; export SHLIB; fi
. $SHLIB/chmod_exit_err.sh # Function dependencies
. $SHLIB/cp_dev_null_exit_err.sh
. $SHLIB/email_msg.sh # Calls $SHLIB/exit.sh
. $SHLIB/ping_host.sh
. $SHLIB/rm_exit_err.sh
: ${id_num=`id|sed 's/^\(uid=\)\([0-9]*\)\(.*\)/\2/'`}
: ${id_hex=`echo "obase=16;$id_num"|bc`}
: ${script_name:=`basename $0`}
: ${name_root:=`echo $script_name|$AWK '{sub(/^\.+/,"");sub(/\..*/,"");print}'`}
: ${yymmddhhmiss:=`date '+%y''%m%d%H''%M''%S'`}
: ${Xtimestamp:=`echo "obase=16;$yymmddhhmiss+$$"|bc`}
: ${sp:=" "}
: ${tmp:=/var/tmp}
FTPH_ID="$script_name($FTPH_name)"
FTPH_usage=`$AWK -v sp="$sp" \
-v FTPH_name="$FTPH_name" \
-v script_name="$script_name" \
'BEGIN \
{
print sp"Usage: "FTPH_name" -dpvt sss host" ,
"\047ftp_command\047 [...]\n" ,
"\n"sp" -d = Use FTP debug option." ,
"\n"sp" -n = No ping to host (for firewall",
"\n"sp" restricted hosts)." ,
"\n"sp" -v = Use FTP verbose option." ,
"\n"sp" -t = Terminate FTP after sss seconds\n"
}'`
#----------------------------#
# Parse any function options.#
#----------------------------#
FTPH_option=0
FTPH_debug=0
FTPH_no_ping=0
FTPH_vervose=0
FTPH_sss=86400
FTPH_opts=""
FTPH_root=$tmp/$name_root"_FTPH_go_"$id_hex
FTPH_err=$FTPH_root"."$Xtimestamp
while getopts dnvt: FTPH_opt 2>> $FTPH_err
do
#---------------------------------------------------------------#
# The FTPH_option and FTPH_opt_l are necessary to prevent #
# possible command options (which must be specified after #
# function options) from being confused with function options. #
#---------------------------------------------------------------#
case $FTPH_opt in
d ) FTPH_opts="${FTPH_opts}d"
FTPH_option=1
;;
n ) FTPH_no_ping=1
FTPH_option=1
;;
v ) FTPH_opts="${FTPH_opts}v"
FTPH_option=1
;;
t ) FTPH_sss="$OPTARG"
FTPH_option=1
#----------------------------------------------#
# Make certain seconds is numeric--exit if no. #
#----------------------------------------------#
FTPH_num=` expr "$FTPH_sss" : "[0-9]*"` # Number of digits
FTPH_chars=`expr "$FTPH_sss" : ".*"` # Total num chars
if [ $FTPH_num -ne $FTPH_chars ]; then
EMAIL_MSG "ERROR (Function): $FTPH_ID" \
"${sp}Invalid seconds following -t option." \
"$FTPH_usage"
return 255
fi
FTPH_sss=`expr $FTPH_sss + 1`
;;
\? ) echo "$FTPH_ID" \
"Invalid option: -`sed 's/^.*-- //' $FTPH_err`" 1>&2
;;
* ) ;;
esac
done
# Shift past options to remaining args
[ $FTPH_option -ne 0 ] && shift `expr $OPTIND - 1`
[ ."$FTPH_root" != . ] && \rm -f $FTPH_root* > /dev/null 2>&1
[ ."$FTPH_opts" != . ] && FTPH_opts="-$FTPH_opts"
#----------------------------------------------------------------#
# Must reset this dog if this function is apt to be called again #
OPTIND=1 # (try and find this fact documented anywhere else). #
#----------------------------------------------------------------#
if [ $# -lt 2 ]; then
EMAIL_MSG "ERROR (Function): $FTPH_ID" \
"${sp}Insufficient args." \
"$FTPH_usage"
return 255
fi
FTPH_host=$1; shift
#------------------------------------------------------#
# PING_HOST tries up tp 10 times. Returns ping status.#
#------------------------------------------------------#
if [ $FTPH_no_ping -ne 0 ]; then
PING_HOST $FTPH_host
if [ $? -ne 0 ]; then
echo "`date '+%Y-%m-%d %T'` ERROR (Comm): $FTPH_ID" 1>&2
echo "${sp}Unable to ping $FTPH_host!" 1>&2
echo "${sp}FTP operation terminated." 1>&2
return 1
fi
fi
#------------------------------------------------------------------#
# OK, we can ping the dog. Build a script and try FTP'ng the file.#
#------------------------------------------------------------------#
FTPH_script=$tmp/$name_root"_FTPH_sc_"$id_hex"."$Xtimestamp
FTPH_stdout=$tmp/$name_root"_FTPH_s1_"$id_hex"."$Xtimestamp
FTPH_stderr=$tmp/$name_root"_FTPH_s2_"$id_hex"."$Xtimestamp
FTPH_pidfil=$tmp/$name_root"_FTPH_PI_"$id_hex"."$Xtimestamp
CP_DEV_NULL_EXIT_ERR $FTPH_script $FTPH_stdout $FTPH_stderr \
$FTPH_pidfil
CHMOD_EXIT_ERR go-w $FTPH_script $FTPH_stdout $FTPH_stderr \
$FTPH_pidfil
CHMOD_EXIT_ERR 0600 $FTPH_script $FTPH_stdout $FTPH_stderr \
$FTPH_pidfil
for FTPH_arg
do
/bin/echo "$FTPH_arg" >> $FTPH_script
FTPH_echo_status=$?
if [ $FTPH_echo_status -ne 0 ]; then
EMAIL_MSG "ERROR: $FTPH_ID" \
"${sp}Problems echoing \"$FTPH_arg\" to $FTPH_script!" \
"${sp}$script_name terminated."
return 255
fi
done
echo "quit" >> $FTPH_script # In case the user forgets this.
#-----------------------------------------------#
# OK, here's what we're paid the big bucks for. #
#-----------------------------------------------#
ftp -n $FTPH_opts $FTPH_host < $FTPH_script \
1> $FTPH_stdout 2> $FTPH_stderr & # <== Note: background process
FTPH_pid=$! # Save BG process ID ($!)
echo $FTPH_pid > $FTPH_pidfil
FTPH_death_certificate="FTP process assinated"
#----------------------------------------------------------------#
# Now wait for the dog to complete (or be assassinated). #
# #
echo "Waiting for FTP operation ($FTPH_pid) to complete." \
>> $FTPH_stdout #
# echo "Sleep \$FTPH_sss=$FTPH_sss">>$FTPH_stdout ## T E S T ## #
#-----------------------------------------------------------# #
# The following background task will terminate the FTP # #
# process with a '-9' if, after sleeping, we find the dog # #
# is still trying run. We cancel this by first removing # #
# the file, $tmpwrk, then killing this entire background # #
# process as well. # #
# # #
( # #
sleep $FTPH_sss # #
if [ -s $FTPH_pidfil ]; then # #
echo "$KILL -9 $FTPH_pid $FTPH_sleep_pid" \
"(FTP & sleep process)" >> $FTPH_stdout # #
$KILL -9 $FTPH_pid >> $FTPH_stdout 2>&1 # #
echo "$FTPH_death_certificate" > $FTPH_pidfil # #
fi # #
) & # #
FTPH_ninja=$! # #
# # #
#-----------------------------------------------------------# #
wait $FTPH_pid # Wait for FTP operation to finish #
# #
#----------------------------------------------------------------#
#--------------------------------------------------------------#
# When the FTP operation completes (either normally or by #
# unnatural causes), remove $FTPH_pidfil and kill the assassin #
# process (if it's still lurking about). #
#--------------------------------------------------------------#
if [ ."`cat $FTPH_pidfil`" != ."$FTPH_death_certificate" ]; then
#-------------------------------------------------#
# Use ptree command to capture sleep (child) PID. #
#-------------------------------------------------#
FTPH_sleep_pid=`/usr/proc/bin/ptree $FTPH_ninja \
| $AWK '/sleep '$FTPH_sss'/ {print $1}'`
echo "$KILL -9 $FTPH_ninja $FTPH_sleep_pid" \
"(assassin & sleep processes)" >> $FTPH_stdout
$KILL -9 $FTPH_sleep_pid $FTPH_ninja >> $FTPH_stdout 2>&1
echo "FTP Completed OK. Assassin terminated." >> $FTPH_stdout
fi
#------------------------------------------------------#
# Get rid of $FTPH_script file right away (because #
# of the likelihood that it has a password in it). #
# Because output is redirected, RM_EXIT_ERR won't exit.#
#------------------------------------------------------#
RM_EXIT_ERR $FTPH_script $FTPH_pidfil >> $FTPH_stdout 2>&1
#-----------------------------------------------------#
# "Command not found happens only if "ftp" is not in #
# the user's path. The rest are true FTP errors. #
#-----------------------------------------------------#
$AWK 'BEGIN {n=0}
{$0=tolower($0)} # Lowercase every line
/login failed/ {n++;next}
/not connected/ {n++;next}
/connection refused/ {n++;next}
/connection timed out/ {n++;next}
/connection reset by peer/ {n++;next}
/no such file or/ {n++;next}
/permission denied/ {n++;next}
/command not found/ {n++;next}
/resource\(s\) in use/ {n++;next}
/no space left on device/ {n++;next}
/broken pipe/ {n++;next}
/please login with user and/ {n++;next}
/ftp process assinated/ {n++;next}
END {exit n}' $FTPH_stdout $FTPH_stderr
FTPH_problems=$?
#----------------------------------------------------#
# If either of these dogs has anything in them, then #
# pass each through stderr or stdout as appropriate. #
#----------------------------------------------------#
[ -s $FTPH_stdout ] && cat $FTPH_stdout # This to stdout
[ -s $FTPH_stderr ] && cat $FTPH_stderr 1>&2 # and this to stderr
\rm -f $FTPH_stdout $FTPH_stderr > /dev/null 2>&1
#----------------------------------------------------------------#
# If no FTP problems, return success, else return $FTPH_problems.#
#----------------------------------------------------------------#
[ $FTPH_problems -eq 0 ] && return 0 || return $FTPH_problems
} # "FTPH_" prefix identifies this function's local variables.
fi
#======================================================================#
# D O C U M E N T A T I O N #
#======================================================================#
# #
# Author: Bob Orlando #
# #
# Date: March 13, 1998 #
# #
# Program ID: ftp_host.sh #
# #
# Usage: FTP_HOST -dnvt sss host "ftp_command" ... #
# -d = Use FTP debug option. #
# -n = No ping to host (for firewall- #
# restricted hosts). #
# -v = Use FTP verbose option. #
# -t sss = Terminate FTP after sss seconds #
# (defaults to 86400 or 24 hrs). #
# #
# Purpose: Issue FTP commands on specified "host", checking for #
# common FTP errors, returning success (0) only when no #
# errors are found. FTP's stdout and stderr output are #
# written to either stdout or stderr, respectively, #
# where the user can process them as needed. #
# #
# Calls: Shell library functions: CHMOD_EXIT_ERR, #
# CP_DEV_NULL_EXIT_ERR, #
# EMAIL_MSG, and #
# PING_HOST. #
# #
# Globals: If unassigned, the following global variables are #
# are assigned: script_name #
# name_root #
# yymmddhhmiss #
# Xtimestamp #
# sp #
# #
# "FTPH_" prefix identifies local function variables. #
# #
# Exit_status: 255 for function error (e.g. user supplies invalid #
# arguments). Else, function returns success or failure #
# of FTP operation. Failure, while not indicated by #
# FTP's exit status may also be signaled by $ftp_problems #
# exceeding 0. Finally, it is the caller's responsibility #
# to capture/redirect stdout and stderr as needed (see #
# "Example:"). #
# #
# Example: #--------------------------------------------------# #
# # List the files in "/data" (note: indentation and # #
# # continuation style used in the this example are # #
# # for readability only--they are NOT required for # #
# # this process' successful operation). # #
# #--------------------------------------------------# #
# FTP_HOST hawkings "cd pub/hosttable" \ #
# "ls abc[0-9][0-9][0-9][0-9].fil" \ #
# "quit" > $stdout 2> $stderr #
# #-------------------------------------------------# #
# # Indent vanilla output with appropriate spaces. # #
# #-------------------------------------------------# #
# [ -s $stdout ] \ #
# && sed "s/^/${stdout_sp}/" $stdout | $teelog #
# [ -s $stderr ] \ #
# && sed "s/^/${stderr_sp}/" $stderr | $teelog #
# #
# Notes: The user may test the error variables directly (see #
# FTPH_problems above) to see precisely which are #
# determined to be errors. #
# #
# Modified: 2004-03-03 Bob Orlando #
# v1.7 * Change set|egrep|awk to just set|egrep. #
# #
#----------------------------------------------------------------------#
|