#!/bin/ksh
#
# $Revision: 1.8 $ $Date: 2012-07-26 17:11:47-04 $
# $Source: /home/vogelke/bin/RCS/gzdir,v $
# $Host: sys7.com $
# $UUID: fb7c43c7-8914-379c-a359-8b0f21ab1b7d $
#
#<gzdir: creates gzipped tarfiles of directory trees.
# usage: gzdir dir [dir ...]
# Defaults: none - you need to specify at least one directory.
# $TMPDIR is used for temp files.
# Required: GNU version of tar, touch.

PATH=/usr/local/bin:/bin:/usr/bin:/opt/sfw/bin
export PATH
tag=${0##*/}

# General logging.
isodate () {
    date '+%Y-%m-%d %H:%M:%S'
}

logmsg () {
    echo "$(isodate): $tag: $@"
}

# Temp file.
err=$(mktemp -q /tmp/$tag.XXXXXX)
case "$?" in
    0)  ;;
    *)  logmsg "FATAL: mktemp errfile rc=$?"; exit 1 ;;
esac

die () {
    logmsg "FATAL: $@"
    test -f $err && rm $err
    exit 1
}

warn () {
    logmsg "WARN: $@"
}

# Log a command, run it, and check for errors.
run () {
    logmsg "$@"
    $@ 2> $err
    test -s "$err" && logger -t $tag -f $err && rm $err && exit 1
}

# Make sure we can get to the temporary directory and back.
: ${TMPDIR=/tmp}
tdir=$TMPDIR

top="$(pwd)"
cd "$tdir" || die "$tdir: can't cd to tmpdir"
tdir="$(pwd)"

# Use a safe pathname for our temporary tarfile.
tfile=$(mktemp -q $tdir/$tag.XXXXXX)
case "$?" in
    0)  ;;
    *)  logmsg "FATAL: mktemp tarfile rc=$?"; exit 1 ;;
esac

# MAIN LOOP

case "$#" in
    0) echo "usage: $tag dir [dir ...]" >&2; exit 1 ;;
    *) ;;
esac

for clean in $*
do
    # Always start from a known location.
    cd "$top"

    # Valid directory?
    test -d "$clean" || die "$clean: not a directory"
    cd "$clean"      || die "$clean: can't cd"
    cwd="$(pwd)"

    # Keep the current modification time of directory to be cleaned.
    # Examples:  Modify: Tue Feb 23 20:22:31 2010
    #            Modify: 2010-02-23 20:03:57.318178000 -0500

    set X $(stat . | grep Modify)
    case "$#" in
        7) modtime="$3 $4 $5 $6 $7" ;;
        5) modtime="$3 $4 $5" ;;
        *) warn "stat $cwd failed"; modtime='now' ;;
    esac

    # Already been run?
    out="arch.tgz"
    test -f "$out" && warn "$clean: $out exists, skipping" && continue

    # Don't clean mount points, your home directory, etc.
    set X $(/bin/df -k . | grep -v '^Filesystem')
    case "$#" in
        7) fsys="$7" ;;
        *) die "df failed" ;;
    esac

    test "$fsys" = "$cwd" && warn "$cwd: is a mountpoint" && continue
    test "$HOME" = "$cwd" && warn "$cwd: is HOME"         && continue
    test "$tdir" = "$cwd" && warn "$cwd: is your tmpdir"  && continue

    # Real work starts here -- we're in the right place.  Ignore error
    # messages from tar about removing the current directory; we could
    # "cd ..", but I want paths relative to the directory.
    tar -cz --remove-files -f $tfile . 2> $err
    egrep -v '.: Cannot rmdir:|Exiting with failure' $err >&2

    # Jump up one directory and recreate this one -- makes it smaller.
    cd ..
    b=$(basename $cwd)
    set X $(stat -c '%U %G %a' "$b")

    case "$#" in
        4) rmdir "$b" && mkdir "$b"
           chown $2 "$b"
           chgrp $3 "$b"
           chmod $4 "$b"
           ;;
        *) warn "stat $cwd failed" ;;
    esac

    # Move the tarfile back.
    cd "$cwd"
    test -s $tfile      || die "$tfile: empty"
    cp $tfile $out      || die "$tfile: cannot copy to $cwd/$out"
    cp /dev/null $tfile || die "$tfile: cannot zero out"

    # Restore directory modification time.
    touch -d "$modtime" .
    chmod 644 $out
done

test -f $err && rm $err
test -f $tfile && rm $tfile
exit 0
