File: //bin/pmlogmv
#!/bin/sh
#
# Copyright (c) 1997,2003 Silicon Graphics, Inc. All Rights Reserved.
# Copyright (c) 2013-2014 Red Hat.
# Copyright (c) 2014 Ken McDonell. All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# Move (rename) a PCP archive.
#
# Operation is atomic across the multiple files of a PCP archive
#
. $PCP_DIR/etc/pcp.env
status=1
tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1
trap "rm -rf $tmp; exit \$status" 0
trap "_cleanup; rm -rf $tmp; exit \$status" 1 2 3 15
prog=`basename $0`
cat > $tmp/usage << EOF
# Usage: [options] oldname newname
Options:
-N, --showme perform a dry run, showing what would be done
-V, --verbose increase diagnostic verbosity
--help
EOF
_usage()
{
pmgetopt --progname=$prog --config=$tmp/usage --usage
exit 1
}
verbose=false
showme=false
LN=ln
RM=rm
RMF="rm -f"
ARGS=`pmgetopt --progname=$prog --config=$tmp/usage -- "$@"`
[ $? != 0 ] && exit 1
eval set -- "$ARGS"
while [ $# -gt 0 ]
do
case "$1"
in
-N) # show me
showme=true
LN='echo >&2 + ln'
RM='echo >&2 + rm'
RMF='echo >&2 + rm -f'
;;
-V) # verbose
verbose=true
;;
--)
shift
break
;;
-\?)
_usage
# NOTREACHED
;;
esac
shift
done
if [ $# -ne 2 ]
then
_usage
# NOTREACHED
fi
# need to handle compression suffixes at the end of a file name
#
eval `pmconfig -L -s compress_suffixes`
if [ -n "$compress_suffixes" ]
then
pat=`echo $compress_suffixes | sed -e 's/\.//g' -e 's/ /|/g' -e 's/^/(/' -e 's/$/)/'`
else
# fallback to a fixed list, as of PCP 4.0.1
#
pat='(xz|lzma|bz2|bz|gz|Z|z)'
fi
if [ -f "$1" ]
then
# oldname is an existing file, strip any compression suffix,
# then strip the expected PCP suffix
#
if echo "$1" | egrep -q "\\.$pat\$"
then
base=`echo "$1" | sed -e 's/\.[a-zA-Z][a-zA-Z0-9]*$//'`
else
base="$1"
fi
case "$base"
in
*[0-9])
old=`echo "$base" | sed -e 's/\.[0-9][0-9]*$//'`
;;
*.index|*.meta)
old=`echo "$base" | sed -e 's/\.[a-z][a-z]*$//'`
;;
*)
echo >&2 "$prog: Error: oldname argument ($1) is not a PCP archive"
exit
;;
esac
else
old="$1"
fi
new="$2"
_cleanup()
{
if [ -f $tmp/old ]
then
for f in `cat $tmp/old`
do
if [ ! -f "$f" ]
then
part=`echo "$f" | sed -e "s@^$old.@@"`
if [ ! -f "$new.$part" ]
then
echo >&2 "$prog: Fatal: $f and $new.$part lost"
ls -l "$old"* "$new"*
rm -f $tmp/old
return
fi
$verbose && echo >&2 "cleanup: recover $f from $new.$part"
if eval $LN "$new.$part" "$f"
then
:
else
echo >&2 "$prog: Fatal: ln $new.$part $f failed!"
ls -l "$old"* "$new"*
rm -f $tmp/old
return
fi
fi
done
fi
if [ -f $tmp/new ]
then
for f in `cat $tmp/new`
do
$verbose && echo >&2 "cleanup: remove $f"
eval $RMF "$f"
done
rm -f $tmp/new
fi
exit
}
# count hard links to a file
#
_count_links()
{
case "$PCP_PLATFORM"
in
# for *BSD-base systems with a -f option to stat(1)
#
darwin|freebsd|netbsd|openbsd)
stat -f '%l' $1
;;
# for Linux systems with a -c option to stat(1)
#
*)
stat -c '%h' $1
;;
esac
}
# get oldnames inventory check required files are present
#
ls "$old".* 2>&1 \
| egrep '\.((index|meta|[0-9][0-9]*)|((index|meta|[0-9][0-9]*)\.'"$pat"'))$' >$tmp/old
if [ -s $tmp/old ]
then
# $old may be an ambiguous suffix, e.g. 20140417.00 (with more than
# one .HH archives) ... pick the suffixes and make sure there are
# no duplicates
#
touch $tmp/ok
cat $tmp/old \
| while read fname
do
if echo "$fname" | egrep -q "\\.$pat\$"
then
echo "$fname" | sed -e 's/\.[a-zA-Z0-9]$//'
else
echo "$fname"
fi
done \
| sed \
-e 's/.*\.index$/index/' \
-e 's/.*\.meta$/meta/' \
-e 's/.*\.\([0-9][0-9]*\)$/\1/' \
| sort \
| uniq -c \
| while read c x
do
case $c
in
1)
;;
*)
echo >&2 "$prog: Error: oldname argument ($old) is a prefix for multiple PCP archive files:"
grep "\\.$x\$" $tmp/old | sed -e 's/^/ /' >&2
rm -f $tmp/ok
;;
esac
done
[ -f $tmp/ok ] || exit
else
echo >&2 "$prog: Error: cannot find any files for the input archive ($old)"
exit
fi
if grep -q '\.[0-9][0-9]*$' $tmp/old
then
:
elif egrep -q '\.[0-9][0-9]*\.'"$pat"'$' $tmp/old
then
:
else
echo >&2 "$prog: Error: cannot find any data files for the input archive ($old)"
ls -l "$old"* >&2
echo "Inspecting files in this list ..." >&2
cat $tmp/old >&2
exit
fi
if grep -q '\.meta$' $tmp/old
then
:
elif egrep -q '\.meta\.'"$pat"'$' $tmp/old
then
:
else
echo >&2 "$prog: Error: cannot find .meta file for the input archive ($old)"
ls -l "$old"* >&2
echo "Inspecting files in this list ..." >&2
cat $tmp/old >&2
exit
fi
# (hard) link oldnames and newnames
#
for f in `cat $tmp/old`
do
if [ ! -f "$f" ]
then
echo >&2 "$prog: Error: ln-pass: input file vanished: $f"
ls -l "$old"* "$new"*
_cleanup
# NOTREACHED
fi
part=`echo "$f" | sed -e "s@^$old.@@"`
if [ -f "$new.$part" ]
then
echo >&2 "$prog: Error: ln-pass: output file already exists: $new.$part"
ls -l "$old"* "$new"*
_cleanup
# NOTREACHED
fi
$verbose && echo >&2 "link $f -> $new.$part"
echo "$new.$part" >>$tmp/new
if eval $LN "$f" "$new.$part"
then
:
else
echo >&2 "$prog: Error: ln $f $new.$part failed!"
ls -l "$old"* "$new"*
_cleanup
# NOTREACHED
fi
done
# unlink oldnames provided link count is 2
#
for f in `cat $tmp/old`
do
if [ ! -f "$f" ]
then
echo >&2 "$prog: Error: rm-pass: input file vanished: $f"
ls -l "$old"* "$new"*
_cleanup
# NOTREACHED
fi
links=`_count_links $f`
xpect=2
$showme && xpect=1
if [ -z "$links" -o "$links" != $xpect ]
then
echo >&2 "$prog: Error: rm-pass: link count "$links" (not $xpect): $f"
ls -l "$old"* "$new"*
_cleanup
fi
$verbose && echo >&2 "remove $f"
if eval $RM "$f"
then
:
else
echo >&2 "$prog: Warning: rm $f failed!"
fi
done
status=0