diff --git a/scripts/upload.sh b/scripts/upload.sh index 185d067d..d75e1cf8 100644 --- a/scripts/upload.sh +++ b/scripts/upload.sh @@ -33,6 +33,7 @@ MYNAME=`basename $0` HOST=ftp.jannet.de CFG_FILE=$HOME/.uploadrc +user=`whoami` method=rsync_ssh pw_ftp= pw_scp=$HOME/.ssh/identity @@ -51,17 +52,29 @@ cat << EOT Unified Upload Interface Version '$Revision$' - '$Date$' - (c) 2002 Jannet IT Services + (c) 2002 Jannet IT Services http://www.jannet.de - usage: $MYNAME file [password:[method:]]user@host:/path/to/directory[:mode[:dirmode[:owner.group]]] ... + usage: $MYNAME file [[password:[method:]user@]]]host:[target[:mode[:dirmode[:owner[.group]]]]] ... where "method" is one of "ftp", "scp", "rsync", "rsync_ssh". + "password" may be a valid rsa private key file, too, if this makes sense with the chosen method. - The default values for the optional parameters may be redefined in $CFG_FILE. + "file" may be a directory and a file. If it ends with a slash, it is treated as an existing + directory and expands to its contents. + + "target" may be a directory and a file. + + If it is an existing directory, it will be populated with "file", "file" will keep its name. + + If it is not an existing directory, $MYNAME will take the path from target (i.e., skip + everything following the last slash), and populate it with "file". + - If there is a nonempty file name following the last slash, this will be the new file name. + - If the last character of the target is a slash, the file name will be taken from "file". + + The default values for the optional parameters can be redefined in $CFG_FILE. Currently they are: + user="$user" method="$method" pw_ftp="$pw_ftp" pw_scp="$pw_scp" @@ -76,5 +89,121 @@ EOT [ -n "$1" ] && exit $1 } +parse_target() +{ + target=$1 + USER=`echo $target | sed -e '/@/ !d; s/@.*//; s/.*://'` + test -n "$USER" && echo user="\"$USER\";" + METHOD=`echo :$target | sed -e '/@/ !d; s/@.*//' | rev | cut -d: -f2 | rev` + test -n "$METHOD" && echo method="\"$METHOD\";" + PASSWD=`echo :$target | sed -e '/@/ !d; s/@.*//' | rev | cut -d: -f3 | rev` + if [ -n "$PASSWD" ]; then + echo passwd="\"$PASSWD\";" + if [ -f "$PASSWD" ]; then + echo IDENTITY="\"-i $PASSWD\"" + fi + echo pw_ftp="\"$PASSWD\";" + echo pw_scp="\"$PASSWD\";" + echo pw_rsync="\"$PASSWD\";" + echo pw_rsync_ssh="\"$PASSWD\";" + fi + HOST=`echo $target | sed -e 's/.*@//' | cut -d: -f1` + if [ -n "$HOST" ]; then + echo host="\"$HOST\";" + else + PARSE_TARGET=FALSE + return + fi + TARGET_FILE=`echo $target | sed -e 's/.*@//' | cut -d: -f2` + if [ -n "$TARGET_FILE" ]; then + echo target_file="\"$TARGET_FILE\";" + else + PARSE_TARGET=FALSE + return + fi + FILE_MODE=`echo $target | sed -e 's/.*@//' | cut -d: -f3` + test -n "$FILE_MODE" && echo file_mode="\"$FILE_MODE\";" + DIR_MODE=`echo $target | sed -e 's/.*@//' | cut -d: -f4` + test -n "$DIR_MODE" && echo dir_mode="\"$DIR_MODE\";" + FILE_OWNER=`echo $target | sed -e 's/.*@//' | cut -d: -f5 | cut -d. -f1` + test -n "$FILE_OWNER" && echo file_owner="\"$FILE_OWNER\";" + FILE_GROUP=`echo $target | sed -e 's/.*@//' | cut -d: -f5 | cut -d. -f2` + test -n "$FILE_GROUP" && echo file_group="\"$FILE_GROUP\";" + + echo "PARSE_TARGET=\"OK\";" +} + +ssh_mkdir() +{ + set -e + dir=`echo $1 | sed -e 's/\/[^\/]*$//; s/\/*$//'` + parts="`echo $dir | sed -e 's/\// /g'`" + test -n "$dir_mode" && MODE="-m $dir_mode" +cat << EOT | + for part in $parts; do + path="\$path/\$part" + if [ ! -d \$path ]; then + mkdir \$path || break + test -n "$2" && chown "$2" \$path || break + test -n "$3" && chgrp "$3" \$path || break + test -n "$4" && chmod "$4" \$path || break + fi + if [ ! -d \$path ]; then + echo "failed to create directory \$path, owner=\$file_owner, group=\$file_group, mode=\$dir_mode" + exit 2 + fi + done +EOT + ssh -l $user $IDENTITY $host -C "SCRIPT=\`mktemp /tmp/$MYNAME""_XXXXXX\`; cat > \$SCRIPT; /bin/sh \$SCRIPT; rm \$SCRIPT" +} + # -- here we go test $# -lt 2 && usage 1 + +# -- get parameters from command line +source=$1 +shift + +# -- check run +for t in $*; do + # parse_target $t + eval `parse_target $t` + if [ "$PARSE_TARGET" != OK ]; then + echo "Failed to parse target \"$t\"; exiting." + parse_target $t + exit 2 + fi + test "$METHOD" && method=$METHOD + case $method in + rsync_ssh) + if [ "$user" != root ]; then + if [ "$file_owner" -a "$file_owner" != "$user" ]; then + echo "File owner \"$file_owner\" is only legal, if you log in as \"$user\" or as \"root\"." + exit 1 + fi + fi + if [ ! -d "$source" -a ! -f "$source" -a ! -L "$source" ]; then + echo \"$source\" is neither a regular file, nor a directory, nor a link. Exiting. >&2 + exit 1 + fi;; + *) + echo "Support for method \"$method\" is not implemented." >&2 + exit 1;; + esac +done + +# -- real run +for t in $*; do + eval `parse_target $t` + test "$METHOD" && method=$METHOD + case $method in + rsync_ssh) + ssh_mkdir $target_file $file_owner $file_group $dir_mode || break + /usr/bin/rsync -az --links -e "/usr/bin/ssh -l $user $IDENTITY" $source $user@$host:$target_file + ;; + *) + echo "Internal error: \"$method\" is not implemented." >&2 + exit 1;; + esac +done +