URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [insight/] [expect/] [example/] [rftp] - Rev 1776
Go to most recent revision | Compare with Previous | Blame | View Log
#!../expect -f
# rftp - ftp a directory hierarchy (i.e. recursive ftp)
# Version 2.10
# Don Libes, NIST
exp_version -exit 5.0
# rftp is much like ftp except that the command ~g copies everything in
# the remote current working directory to the local current working
# directory. Similarly ~p copies in the reverse direction. ~l just
# lists the remote directories.
# rftp takes an argument of the host to ftp to. Username and password
# are prompted for. Other ftp options can be set interactively at that
# time. If your local ftp understands .netrc, that is also used.
# ~/.rftprc is sourced after the user has logged in to the remote site
# and other ftp commands may be sent at that time. .rftprc may also be
# used to override the following rftp defaults. The lines should use
# the same syntax as these:
set file_timeout 3600 ;# timeout (seconds) for retrieving files
set timeout 1000000 ;# timeout (seconds) for other ftp dialogue
set default_type binary ;# default type, i.e., ascii, binary, tenex
set binary {} ;# files matching are transferred as binary
set ascii {} ;# as above, but as ascii
set tenex {} ;# as above, but as tenex
# The values of binary, ascii and tenex should be a list of (Tcl) regular
# expressions. For example, the following definitions would force files
# ending in *.Z and *.tar to be transferred as binaries and everything else
# as text.
# set default_type ascii
# set binary {*.Z *.tar}
# If you are on a UNIX machine, you can probably safely ignore all of this
# and transfer everything as "binary".
# The current implementation requires that the source host be able to
# provide directory listings in UNIX format. Hence, you cannot copy
# from a VMS host (although you can copy to it). In fact, there is no
# standard for the output that ftp produces, and thus, ftps that differ
# significantly from the ubiquitous UNIX implementation may not work
# with rftp (at least, not without changing the scanning and parsing).
####################end of documentation###############################
match_max -d 100000 ;# max size of a directory listing
# return name of file from one line of directory listing
proc getname {line} {
# if it's a symbolic link, return local name
set i [lsearch $line "->"]
if {-1==$i} {
# not a sym link, return last token of line as name
return [lindex $line [expr [llength $line]-1]]
} else {
# sym link, return "a" of "a -> b"
return [lindex $line [expr $i-1]]
}
}
proc putfile {name} {
global current_type default_type
global binary ascii tenex
global file_timeout
switch -- $name $binary {set new_type binary} \
$ascii {set new_type ascii} \
$tenex {set new_type tenex} \
default {set new_type $default_type}
if {$current_type != $new_type} {
settype $new_type
}
set timeout $file_timeout
send "put $name\r"
expect timeout {
send_user "ftp timed out in response to \"put $name\"\n"
exit
} "ftp>*"
}
proc getfile {name} {
global current_type default_type
global binary ascii tenex
global file_timeout
switch -- $name $binary {set new_type binary} \
$ascii {set new_type ascii} \
$tenex {set new_type tenex} \
default {set new_type $default_type}
if {$current_type != $new_type} {
settype $new_type
}
set timeout $file_timeout
send "get $name\r"
expect timeout {
send_user "ftp timed out in response to \"get $name\"\n"
exit
} "ftp>*"
}
# returns 1 if successful, 0 otherwise
proc putdirectory {name} {
send "mkdir $name\r"
expect "550*denied*ftp>*" {
send_user "failed to make remote directory $name\n"
return 0
} timeout {
send_user "timed out on make remote directory $name\n"
return 0
} -re "(257|550.*exists).*ftp>.*"
# 550 is returned if directory already exists
send "cd $name\r"
expect "550*ftp>*" {
send_user "failed to cd to remote directory $name\n"
return 0
} timeout {
send_user "timed out on cd to remote directory $name\n"
return 0
} -re "2(5|0)0.*ftp>.*"
# some ftp's return 200, some return 250
send "lcd $name\r"
# hard to know what to look for, since my ftp doesn't return status
# codes. It is evidentally very locale-dependent.
# So, assume success.
expect "ftp>*"
putcurdirectory
send "lcd ..\r"
expect "ftp>*"
send "cd ..\r"
expect timeout {
send_user "failed to cd to remote directory ..\n"
return 0
} -re "2(5|0)0.*ftp>.*"
return 1
}
# returns 1 if successful, 0 otherwise
proc getdirectory {name transfer} {
send "cd $name\r"
# this can fail normally if it's a symbolic link, and we are just
# experimenting
expect "550*ftp>*" {
send_user "failed to cd to remote directory $name\n"
return 0
} timeout {
send_user "timed out on cd to remote directory $name\n"
return 0
} -re "2(5|0)0.*ftp>.*"
# some ftp's return 200, some return 250
if $transfer {
send "!mkdir $name\r"
expect "denied*" return timeout return "ftp>"
send "lcd $name\r"
# hard to know what to look for, since my ftp doesn't return
# status codes. It is evidentally very locale-dependent.
# So, assume success.
expect "ftp>*"
}
getcurdirectory $transfer
if $transfer {
send "lcd ..\r"
expect "ftp>*"
}
send "cd ..\r"
expect timeout {
send_user "failed to cd to remote directory ..\n"
return 0
} -re "2(5|0)0.*ftp>.*"
return 1
}
proc putentry {name type} {
switch -- $type \
d {
# directory
if {$name=="." || $name==".."} return
putdirectory $name
} - {
# file
putfile $name
} l {
# symlink, could be either file or directory
# first assume it's a directory
if [putdirectory $name] return
putfile $name
} default {
send_user "can't figure out what $name is, skipping\n"
}
}
proc getentry {name type transfer} {
switch -- $type \
d {
# directory
getdirectory $name $transfer
} - {
# file
if !$transfer return
getfile $name
} l {
# symlink, could be either file or directory
# first assume it's a directory
if [getdirectory $name $transfer] return
if !$transfer return
getfile $name
} default {
send_user "can't figure out what $name is, skipping\n"
}
}
proc putcurdirectory {} {
send "!/bin/ls -alg\r"
expect timeout {
send_user "failed to get directory listing\n"
return
} "ftp>*"
set buf $expect_out(buffer)
for {} 1 {} {
# if end of listing, succeeded!
if 0==[regexp "(\[^\n]*)\n(.*)" $buf dummy line buf] return
set token [lindex $line 0]
switch -- $token \
!/bin/ls {
# original command
} total {
# directory header
} . {
# unreadable
} default {
# either file or directory
set name [getname $line]
set type [string index $line 0]
putentry $name $type
}
}
}
# look at result of "dir". If transfer==1, get all files and directories
proc getcurdirectory {transfer} {
send "dir\r"
expect timeout {
send_user "failed to get directory listing\n"
return
} "ftp>*"
set buf $expect_out(buffer)
for {} 1 {} {
regexp "(\[^\n]*)\n(.*)" $buf dummy line buf
set token [lindex $line 0]
switch -- $token \
dir {
# original command
} 200 {
# command successful
} 150 {
# opening data connection
} total {
# directory header
} 226 {
# transfer complete, succeeded!
return
} ftp>* {
# next prompt, failed!
return
} . {
# unreadable
} default {
# either file or directory
set name [getname $line]
set type [string index $line 0]
getentry $name $type $transfer
}
}
}
proc settype {t} {
global current_type
send "type $t\r"
set current_type $t
expect "200*ftp>*"
}
proc final_msg {} {
# write over the previous prompt with our message
send_user "\rQuit ftp or cd to another directory and press ~g, ~p, or ~l\n"
# and then reprompt
send_user "ftp> "
}
if [file readable ~/.rftprc] {source ~/.rftprc}
set first_time 1
if $argc>1 {
send_user "usage: rftp [host]
exit
}
send_user "Once logged in, cd to the directory to be transferred and press:\n"
send_user "~p to put the current directory from the local to the remote host\n"
send_user "~g to get the current directory from the remote host to the local host\n"
send_user "~l to list the current directory from the remote host\n"
if $argc==0 {spawn ftp} else {spawn ftp $argv}
interact -echo ~g {
if $first_time {
set first_time 0
settype $default_type
}
getcurdirectory 1
final_msg
} -echo ~p {
if $first_time {
set first_time 0
settype $default_type
}
putcurdirectory
final_msg
} -echo ~l {
getcurdirectory 0
final_msg
}
Go to most recent revision | Compare with Previous | Blame | View Log