jw-pkg/scripts/upload.sh
2002-07-10 12:20:30 +00:00

298 lines
8.9 KiB
Bash

#!/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=
test -f $CFG_FILE && . $CFG_FILE
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"
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
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\""
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\" # TODO: this is bullshit
else
echo target_path=\"$TARGET_FILE/`basename $source`\" # 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 || 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_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:' $*`
while [ "$1" != -- ]; do
case $1 in
h)
usage 0;;
v)
VERBOSE=1;;
c)
VARIABLE=$2
shift;;
*)
usage 1;;
esac
shift
done
shift
test -z "$VARIABLE" && 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
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
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
if [ -n "$VARIABLE" ]; then
eval `parse_target`
case "$VARABLE" 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
exit 0
fi
for t in $*; do
eval `parse_target $t`
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_file $file_owner $file_group
ssh_chmod $target_file $file_mode $dir_mode
;;
*)
echo "Internal error: \"$method\" is not implemented." >&2
exit 1;;
esac
done