#!/bin/sh
#
# fscat - Cat a raw filesystem to an archive.
#
# Copyright (C) 2005 Oracle.  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, version 2, as published by the Free Software Foundation.
# 
# 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.
# 
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 021110-1307, USA.
#

# From configure
VERSION="0.4.4"
prefix="/usr"
exec_prefix="${prefix}"
sbindir="/sbin"

PROGNAME=fscat
DRIVER_DIR="${sbindir}"


#
# Processing parameters
#

# When filename is empty, we write to stdout
FILENAME=
# The default archive is native fscat
ARCHIVE=
# The default compression is none
COMPRESSOR=
# When the fstype is empty, we guess with blkid
FSTYPE=
# The device we're reading from
DEVICE=
# How verbose should the archiver be
VERBOSE=

if [ "$(type which)" = "alias" ]
then
    unalias which
fi

BLKID="$(which blkid 2>/dev/null)"
if [ -z "${BLKID}" ]
then
    BLKID="/sbin/blkid"
fi

if [ ! -x "${BLKID}" ]
then
    BLKID=
fi

print_usage()
{
    RC="$1"

    if [ "$RC" = 0 ]
    then
        OUT=1
    else
        OUT=2
    fi

cat <<EOF >&${OUT}
Usage: ${PROGNAME} [-t <fstype>] [-v] [-j|-z] [-a <archivetype>] [-f <file>] <device>
EOF

    exit $RC
}

print_version()
{
    echo "${PROGNAME} version ${VERSION}"
    exit 0
}

while getopts ":t:a:f:zjvhV-:" opt
do
    case "$opt" in
    f)
        # Treat '-' as stdout
        if [ "${OPTARG}" != "-" ]
        then
            FILENAME="${OPTARG}"
        fi
        ;;
    t)
        FSTYPE="${OPTARG}"
        ;;
    z)
        COMPRESSOR="gzip"
        ;;
    j)
        COMPRESSOR="bzip2"
        ;;
    a)
        ARCHIVE="${OPTARG}"
        ;;
    v)
        VERBOSE="${VERBOSE} -v"
        ;;
    h)
        print_usage 0
        ;;
    V)
        print_version
        ;;
    "-")
        case "$OPTARG" in
        "help")
            print_usage 0
            ;;
        "version")
            print_version
            ;;
        *)
            echo "${PROGNAME}: Unknown option '-${OPTARG}'" >&2
            print_usage 1
            ;;
        esac
        ;;
    ":")
        echo "${PROGNAME}: Option '-${OPTARG}' requires an argument" >&2
        print_usage 1
        ;;
    "?")
        echo "${PROGNAME}: Unknown option: '-${OPTARG}'" >&2
        print_usage 1
        ;;
    *)
        echo "${PROGNAME}: What the?  Option parsing" >&2
        print_usage 1
        ;;
    esac
done

shift $(expr ${OPTIND} - 1)

DEVICE="$1"

if [ -z "$DEVICE" ]
then
    echo "${PROGNAME}: No device specified" >&2
    print_usage 1
fi

if [ ! -e "${DEVICE}" ]
then
    echo "${PROGNAME}: Device \"${DEVICE}\" does not exist" >&2
    exit 1
fi

if [ ! -r "$DEVICE" ]
then
    echo "${PROGNAME}: Unable to access device \"${DEVICE}\"" >&2
    exit 1
fi

if [ -z "$FSTYPE" ]
then
    FSTYPE=$(/sbin/blkid -s TYPE "${DEVICE}" | sed -e 's/^[^"]*TYPE="\(.*\)".*$/\1/')
fi

if [ -z "$FSTYPE" ]
then
    echo "${PROGNAME}: Cannot determine filesystem type on \"${DEVICE}\"." >&2
    exit 1
fi

DRIVER="${DRIVER_DIR}/fscat_driver.${FSTYPE}"
if [ ! -x "${DRIVER}" ]
then
    echo "${PROGNAME}: Filesystem type \"${FSTYPE}\" is not supported." >&2
    exit 1
fi

if [ -z "$ARCHIVE" -a -z "$COMPRESSOR" -a -n "$FILENAME" ]
then
    case "$FILENAME" in
    *.bz2)
        COMPRESSOR=bzip2
        STUB="${FILENAME%.bz2}"
        ;;
    *.gz)
        COMPRESSOR=gzip
        STUB="${FILENAME%.gz}"
        ;;
    *)
        STUB="$FILENAME"
        ;;
    esac

    case "$STUB" in
    *.tar)
        ARCHIVE=tar
        ;;
    *.cpio)
        ARCHIVE=cpio
        ;;
    *.fscat)
        ARCHIVE=fscat
        ;;
    *)
        :
        ;;
    esac
fi

if [ -z "$ARCHIVE" ]
then
    ARCHIVE=fscat
fi

ARCHIVER="${DRIVER_DIR}/fscat_archive.${ARCHIVE}"
if [ ! -x "${ARCHIVER}" ]
then
    echo "${PROGNAME}: Archive type \"${ARCHIVE}\" is not supported." >&2
    exit 1
fi


if [ -z "$COMPRESSOR" ]
then
    COMPRESSOR=cat
fi

if [ -z "$FILENAME" ]
then
    "${DRIVER}" -L -0 "${DEVICE}" | "${DRIVER}" -I -0 "${DEVICE}" |
        "${ARCHIVER}" $VERBOSE | "${COMPRESSOR}"
else
    "${DRIVER}" -L -0 "${DEVICE}" | "${DRIVER}" -I -0 "${DEVICE}" |
        "${ARCHIVER}" $VERBOSE | "${COMPRESSOR}" >"${FILENAME}"
fi

exit $?
