#!/bin/sh ######################################################################## # # # generic utiltiy modules # # (c) 2001 jannet it services # # contact@jannet.de # # # # $Id$ # # # This program is free software; permission to use, copy, modify, # # distribute, and sell this software and its documentation under the # # terms of the GNU Public license as published by the Free Software # # Foundation, either version 2 or any later version of the license, is # # hereby granted without fee, provided that (i) the above copyright # # notices and this permission notice appear in all copies of the # # software and related documentation, and (ii) the name of JanNet may # # not be used in any advertising or publicity relating to the software # # without the specific, prior written permission of JanNet. # # # # This program is distributed in the hope that it will be useful, but # # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- # # TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # # Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program; if not, write to the Free Software Founda- # # tion, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # # # ######################################################################## MYNAME=`basename $0` HOST=ftp.jannet.de CFG_FILE=$HOME/.uploadrc login=`whoami` method=rsync_ssh pw_ftp= pw_scp=$HOME/.ssh/identity pw_rsync= pw_rsync_ssh=$HOME/.ssh/identity file_mode= dir_mode= file_owner= file_group= ssh_identity= test -f $CFG_FILE && . $CFG_FILE if [ -n "$ssh_identity" ]; then CFG_IDENTITY="-i $ssh_identity" fi usage() { cat << EOT Unified Upload Interface Version '$Revision$' - '$Date$' (c) 2002 Jannet IT Services http://www.jannet.de usage: $MYNAME -h $MYNAME [-v] [-c variable] source [method://][[password:]login@]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. "source" may be a directory or a file. If it ends with a slash, it is treated as an existing directory and expands to its contents. Thus, in the following, "source" denotes either a single or multiple files or directories. "target" may be a directory or a file. + If it is an existing directory, it will be populated with "source". The name(s) of "source" will be preserved. + If it is not an existing directory, and does not have a trailing slash, $MYNAME will skip everything following the last slash for a directory name, create it, and populate it with "source". "source" will get renamed to the last portion of "target". + If it is not an existing directory and has a trailing slash it will be created and populated with "source". The default values for the optional parameters can be redefined in $CFG_FILE. Currently they are: login="$login" method="$method" pw_ftp="$pw_ftp" pw_scp="$pw_scp" pw_rsync="$pc_rsync" pw_rsync_ssh="$pw_rsync_ssh" file_mode="$file_mode" dir_mode="$dir_mode" file_owner="$file_owner" file_group="$file_group" ssh_identity="$ssh_identity" Options: -h : show this help screen -c variable : show contents of variable valid variables are login, method, passwd, file_owner, file_group, file_mode, dir_mode, source, target_file -p : parse command line into variables, show results and exit if -x switch is active -x : exit after informational commands EOT [ -n "$1" ] && exit $1 } is_dir() { isdir="`echo $1 | sed 's/.*\/$/yes/'`" test "$isdir" = yes } parse_target() { target=$1 LOGIN=`echo $target | sed -e 's/^.*:\/\///; /@/ !d; s/@.*//; s/.*://'` test -n "$LOGIN" && echo login="\"$LOGIN\";" METHOD=`echo $target | sed -e '/:\/\// !d; s/:\/\/.*//'` test -n "$METHOD" && echo method="\"$METHOD\";" PASSWD=`echo $target | sed -e '/@/ !d; /@/ !d; s/^.*:\/\///; s/@.*//' | rev | cut -d: -f2 | rev` if [ -n "$PASSWD" ]; then echo passwd="\"$PASSWD\";" if [ -f "$PASSWD" ]; then echo IDENTITY="\"-i $PASSWD\";" else echo IDENTITY="\"$CFG_IDENTITY\";" 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/^.*:\/\///; s/.*@//' | cut -d: -f1` if [ -n "$HOST" ]; then echo host="\"$HOST\";" else PARSE_TARGET=FALSE return fi TARGET_FILE=`echo $target | sed -e 's/^.*:\/\///; s/.*@//; /:/ !d' | 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/^.*:\/\///; s/.*@//; /:/ !d' | cut -d: -f3` test -n "$FILE_MODE" && echo file_mode="\"$FILE_MODE\";" DIR_MODE=`echo $target | sed -e 's/^.*:\/\///; s/.*@//; /:/ !d' | cut -d: -f4` test -n "$DIR_MODE" && echo dir_mode="\"$DIR_MODE\";" FILE_OWNER=`echo $target | sed -e 's/^.*:\/\///; s/.*@//; /:/ !d' | cut -d: -f5 | cut -d. -f1` test -n "$FILE_OWNER" && echo file_owner="\"$FILE_OWNER\";" FILE_GROUP=`echo $target | sed -e 's/^.*:\/\///; s/.*@//; /:/ !d' | cut -d: -f5 | cut -d. -f2` test -n "$FILE_GROUP" && echo file_group="\"$FILE_GROUP\";" if is_dir "$target_file" ; then echo target_path=\"$TARGET_FILE/`basename $TARGET_FILE`\" # TODO: this is bullshit else echo target_path=\"$TARGET_FILE\" # TODO: this is bullshit fi echo "PARSE_TARGET=\"OK\";" } ssh_exec_stdin() { ssh -l $login $IDENTITY $host -C "SCRIPT=\`mktemp /tmp/$MYNAME""_XXXXXX\`; cat > \$SCRIPT; /bin/sh \$SCRIPT; rm \$SCRIPT" } 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 || continue test -n "$3" && chgrp "$3" \$path || continue test -n "$4" && chmod "$4" \$path || continue 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_exec_stdin } ssh_chown() { set -e dir=`echo $1 | sed -e 's/\/[^\/]*$//; s/\/*$//'` cat << EOT | if [ -f "$1" -a -n "$file_owner" ]; then chown $file_owner $1; fi if [ -f "$1" -a -n "$file_group" ]; then chgrp $file_group $1; fi #cd $1 #if [ -n "$2" ]; then chown -R $2 . ; fi #if [ -n "$3" ]; then chown -R $3 . ; fi EOT ssh_exec_stdin } ssh_chmod() { set -e dir=`echo $1 | sed -e 's/\/[^\/]*$//; s/\/*$//'` cat << EOT | if [ -f "$1" -a -n "$file_mode" ]; then chmod $file_mode $1; fi #if [ -n "$2" ]; then find . -type f | xargs --no-run-if-empty chmod $2 ; fi #if [ -n "$3" ]; then find . -type d | xargs --no-run-if-empty chmod $3 ; fi EOT ssh_exec_stdin } # -- here we go # -- command line arguments set -- `getopt 'hvc:px' $*` while [ "$1" != -- ]; do case $1 in -h) usage 0;; -v) VERBOSE=1;; -c) VARIABLE=$2 shift;; -p) PARSE=1;; -x) EXIT=1;; *) usage 1;; esac shift done shift test -z "$VARIABLE" && test $# -lt 2 && usage 1 # -- get parameters from command line n_targets=`expr $# - 1` target="`echo $* | cut -d' ' -f$#`" source="`echo $* | cut -d' ' -f1-$n_targets`" #echo target=$target #echo source=$source # -- check run for s in $source; do if [ ! -d "$s" -a ! -f "$s" -a ! -L "$s" ]; then echo \"$s\" is neither a regular file, nor a directory, nor a link. Exiting. >&2 exit 1 fi done eval `parse_target $target` if [ "$PARSE_TARGET" != OK ]; then echo "Failed to parse target \"$t\"; exiting." parse_target $t exit 2 fi case $method in rsync_ssh) if [ "$login" != root ]; then if [ "$file_owner" -a "$file_owner" != "$login" ]; then echo "File owner \"$file_owner\" is only legal, if you log in as \"$login\" or as \"root\"." exit 1 fi fi;; *) echo "Support for method \"$method\" is not implemented." >&2 exit 1;; esac # -- real run if [ -n "$VARIABLE" ]; then eval `parse_target` case "$VARIABLE" in login) echo $login;; method) echo $method;; passwd) echo $passwd;; file_owner) echo $file_owner;; file_group) echo $file_group;; file_mode) echo $file_mode;; dir_mode) echo $dir_mode;; source) echo $source;; target_file) echo $target_file;; *) echo Unknown variable \"$VARIABLE\". Exiting. >&2 exit 1; esac test "$EXIT" = 1 && exit 0 fi if [ "$PARSE" = 1 ]; then eval `parse_target` for var in login method passwd file_owner file_group file_mode dir_mode source target_file ; do eval echo $var = \$$var done test "$EXIT" = 1 && exit 0 fi eval `parse_target $target` 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 $login $IDENTITY" $source $login@$host:$target_file ssh_chown $target_path $file_owner $file_group ssh_chmod $target_path $file_mode $dir_mode ;; *) echo "Internal error: \"$method\" is not implemented." >&2 exit 1;; esac