#!/bin/ksh 
#
# ident	"@(#)flarcreate.sh	1.24	05/05/05 SMI"
#
# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#

   ########################################
   #                                      #
   # flarcreate -- Create a Flash Archive #
   #                                      #
   ########################################

TEXTDOMAIN=SUNW_INSTALL_FLASH
export TEXTDOMAIN

# list of required utilities.  If you add any to this
# list, be sure to also add it to the $UTIL_LIST variable below!
AWK="/usr/bin/awk"
SED="/usr/bin/sed"
DF="/usr/sbin/df"
RM="/usr/bin/rm"
CPIO="/usr/bin/cpio"
COMPRESS="/usr/bin/compress"
UUENCODE="/usr/bin/uuencode"
WC="/usr/bin/wc"
CAT="/usr/bin/cat"
UNAME="/usr/bin/uname"
FIND="/usr/bin/find"
TOUCH="/usr/bin/touch"
MT="/usr/bin/mt"
DD="/usr/bin/dd"
ID="/usr/bin/id"
LS="/usr/bin/ls"

UTIL_LIST="$AWK $SED $DF $RM $CPIO $COMPRESS $WC $CAT $UNAME $FIND $TOUCH $MT $DD $ID $LS"

##############################################################
# Function find_utils makes sure required utilies exist.
##############################################################
find_utils_or_exit ()
{
    for i in $UTIL_LIST ; do
	if [ ! -x $i ] ; then
		print_error_and_exit "$(gettext "Required utility %s is not available.")" $i
	fi
    done
}

##############################################################
# Function print_error_and_exit prints a formatted message
# to stderr prefixed with ERROR: and new-lined, and exits 1.
##############################################################

print_error_and_exit ()
{
	typeset format=$1
	shift
	typeset values=$*

	printf "$(gettext 'ERROR:') ${format}\n" $values >&2

	exit 1
}

##############################################################
# Function print_message prints a formatted message to stderr
##############################################################

print_message ()
{
	typeset format=$1
	shift
	typeset values=$*

	printf "${format}\n" $values >&2
}

###############################################################
# Function print_usage_and_exit does just that
###############################################################

print_usage_and_exit ()
{
	# Remember to update the usage in flar if you update this one
	typeset myname=`basename $0`
	print_message "$(gettext "Usage:")"
	print_message "$myname $(gettext '-n name [-R root] [-A old_root] [-t [-p posn] [-b blocksize]]')"
	print_message "             $(gettext '[-i date] [-u section [-d path ]] [-U key=value] [-m master]')"
	print_message "             $(gettext '[-H] [-S] [-c] [-M] [-I] [-f [ list_file | - ] [-F]]')"
	print_message "             $(gettext '[-a author] [-e descr | -E descr_file] [-T type]')"
	print_message "             $(gettext '[[-x exclude_dir/file][-x exclude_dir/file]...] [-X list_file]')"
	print_message "             $(gettext '[[-y include_dir/file [-y include_dir/file]...]')"
	print_message "             $(gettext '[-z filter_list_file]')"
	print_message "             $(gettext 'archive')"
	exit 1
}

##############################################################
# Function print_error_and_usage prints a formatted message to stderr
# with ERROR: and calls print_usage_and_exit
##############################################################

print_error_and_usage ()
{
	typeset format=$1
	shift
	typeset values=$*

	printf "$(gettext 'ERROR:') ${format}\n" $values >&2
	print_usage_and_exit
}

##############################################################
# Functions dial(), start_dial(), stop_dial(), and cleanup()
# implement a spinner of |, /. -, and \. dial() runs in the
# background. Use of traps is critical to avoid spinning after
# user has Control-C'd.
##############################################################

dial()
{
	typeset state=0
	trap - EXIT INT # Set trap to ignore

	while : ; do
		case $state in
		    0)
			echo "|\b\c"   # top-bottom
			state=1
			;;
		    1)
			echo "/\b\c"   # upper right, lower left
			state=2
			;;
		    2)
			echo "-\b\c"   # left-right
			state=3
			;;
		    3)
			echo "\\" "\b\b\c" # upper left, lower right
			state=0 
			;;
		esac

		sleep 1
	done
}
start_dial()
{
	[[ $QUIET = $YES ]] && return
	dial &       # Start in background
	DIALPID=$!   # Get pid, for killing
	trap "cleanup 1" EXIT INT  # Set trap
}
stop_dial()
{
	[[ $QUIET = $YES ]] && return
	trap "" EXIT INT  
	kill $DIALPID >/dev/null 2>&1
	DIALPID=
	echo " \b\c"
}
cleanup()
{
	typeset exitcode=$1

	if [[ ! -z "$DIALPID" ]] ; then
		kill $DIALPID
	fi
	if [[ -x $hash_file ]] ; then
	    ${RM} -f $hash_file
	fi
	exit $exitcode
}

#####################################################################
# Function get_platforms makes a string for the content_architectures
# identification line. It prints the string, so the caller should
# get the string as $(get_platforms).
#####################################################################

get_platforms ()
{
	typeset file="var/sadm/system/admin/.platform"
	typeset entry=
	typeset line=
	typeset values=

	# if there is no $root_directory, then the following argument
	# to grep will be relative to /.  Also, we aren't interested
	# in any error output from grep, all we care is that it failed,
	# so ignore stderr.
	values=$(grep "^PLATFORM_GROUP" $root_directory/$file 2> /dev/null)
	if [[ $? -ne 0 ]]; then
		print $(${UNAME} -m)
		return
	fi
	for entry in $values ; do
		[[ ! -z $line  ]] && line="${line},"
		line="${line}${entry#PLATFORM_GROUP=}"
	done 
	print $line
}

######################################################
# Function size_archive implements the sizing feature
# of flarcreate.
######################################################

size_archive()
{
	# Set up
	archive_size=0
	print_message "$(gettext "Determining the size of the archive...")"
	start_dial

	archive_size=$(gen_archive | \
			${WC} -c |${AWK} '{print $1}')
	status=$?
	stop_dial
	# Clean up
	if [[ $status != 0 || -z "$archive_size" || $archive_size -eq 0 ]]; then
		print_error_and_exit "$(gettext "Unable to find size of intended archive.")"
	fi

	# Print the size
	if [[ ${#archive_size} -gt 9 ]] ; then
		unit="GB"
		div=1073741824
	elif [[ ${#archive_size} -gt 6 ]] ; then
		unit="MB"
		div=1048576
	else
		unit="KB"
		div=1024
	fi

	intnum=$(echo $archive_size / $div |bc)
	fracnum=$(echo $archive_size / \( $div / 100 \) % 100 |bc) 

	print_message "$(gettext "The archive will be approximately %d.%02d%s.")" $intnum $fracnum $unit
}

################################################################
# Function gen_ident_and_cookie outputs the cookie and the 
# identification lines in the output archive. Also outputs any
# user-specified control sections.
################################################################

gen_ident_and_cookie()
{
	typeset keyword
	typeset section
	typeset bad_start
	typeset cookie="FlAsH-aRcHiVe-2.0"
	typeset ident_begin="section_begin=identification"
	typeset hash_key="archive_id="
	typeset hash="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

	hash_length=${#hash}
	hash_offset=`expr ${#cookie} + 1 + ${#ident_begin} + 1 + ${#hash_key}`
	hash_file=/tmp/.flarcreate.hash.$$
	${CAT} <<-EOF
		$cookie
		$ident_begin
	EOF

	if [[ $generate_hash = $YES ]] ; then
	    if [ -z "${COMPUTEHASH}" ] ; then
		print_message "$(gettext "WARNING: computehash not found; cannot generate checksums")"
		generate_hash=$NO
	    else
		${COMPUTEHASH} -n
		if [ $? != 0 ] ; then
		    print_message "$(gettext "WARNING: Hash generation only supported on Solaris 8 and later")"
		    generate_hash=$NO
		else
		    echo "${hash_key}${hash}"
		fi
	    fi
	fi

        if [[ $root_directory = "/" ]]; then
                creation_node=`uname -n`
                creation_hardware_class=`uname -m`
                creation_platform=`uname -i`
                creation_processor=`uname -p`
                creation_release=`uname -r`
                creation_os_name=`uname -s`
                creation_os_version=`uname -v`
        else

                creation_node=`cat ${root_directory}/etc/nodename`

                creation_hardware_class="UNKNOWN"
                creation_platform="UNKNOWN"
                creation_processor="UNKNOWN"
                creation_os_version="UNKNOWN"
  
                . ${root_directory}/var/sadm/system/admin/INST_RELEASE

                case $OS in
                        Solaris  )
                        creation_os_name=SunOS
                        case $VERSION in
                            2.* ) creation_release=5.${VERSION#*.} ;;
                            7 )   creation_release=5.7 ;;
                            8 )   creation_release=5.8 ;;
                            9 )   creation_release=5.9 ;;
                        esac
                        ;;
                        *  )
                            creation_os_name=UNKNOWN
                            creation_release=UNKNOWN
                        ;;
                esac
        fi

	${CAT} <<-EOF
		files_archived_method=cpio
		creation_date=$creation_date
		creation_master=$creation_master
		content_name=$content_name
		creation_node=$creation_node
		creation_hardware_class=$creation_hardware_class
		creation_platform=$creation_platform
		creation_processor=$creation_processor
		creation_release=$creation_release
		creation_os_name=$creation_os_name
		creation_os_version=$creation_os_version
	EOF

	if [[ $compress_action = $YES ]]; then
		echo "files_compressed_method=compress"
	else
		echo "files_compressed_method=none"
	fi

	if [[ $sizing_action = $YES ]]; then
		echo "files_archived_size=$archive_size"
	fi

	#### TODO : files_unarchived_size

	if [[ ! -z $content_description ]]; then
		echo "content_description=$content_description"
	fi

	if [[ ! -z $content_type ]]; then
		echo "content_type=$content_type"
	fi

	if [[ ! -z $content_author ]]; then
		echo "content_author=$content_author"
	fi

	echo "content_architectures=$(get_platforms)"

	# Setting Archive type

	echo "type=$FLASH_TYPE"

	for keyword in $new_keywords; do
		if [[ $keyword = "${keyword#X-}" ]]; then
			print_message "$(gettext "Added keyword %s does not begin with %s.")" $keyword "X-"
		fi
		echo $keyword
	done

	echo "section_end=identification"

	# manifest section creation

	if [[ $old_root_directory != "NON_DIFFERENTIAL" ]] ; then
		if [[ $create_manifest != "no" ]] ; then
			echo "section_begin=manifest"
			$FDO dir_state_save $FILTER $root_directory $old_root_directory
			echo "section_end=manifest"
		else
			print_message "$(gettext "WARNING: Skipping manifest creation (-M option set)")"
		fi
	fi

	# predeployment customization scripts section

	echo "section_begin=predeployment"

	# dynamic customer predeployment scripts from $FLASH_DIR/predeployment

	cd $FLASH_DIR
	$FIND predeployment -print | $CPIO -ocO /tmp/flash.predeployment.$$.cpio 2> /tmp/cpout.$$
	if [ $? != 0 ] ; then
		$CAT /tmp/cpout.$$
		$RM /tmp/cpout.$$
		print_error_and_exit "$(gettext "CPIO error during archive creation.")"
	fi

	# flash internal predeployment script

	if [ -e $root_directory/usr/lib/flash/predeployment_processing ] ; then
		cd $root_directory/usr/lib/flash/
		echo predeployment_processing | $CPIO -ocAO /tmp/flash.predeployment.$$.cpio 2> /tmp/cpout.$$
		if [ $? != 0 ] ; then
			$CAT /tmp/cpout.$$
			$RM /tmp/cpout.$$
			print_error_and_exit "$(gettext "CPIO error during archive creation.")"
		fi
	fi

	# static customer predeployment scripts from /etc/flash/predeployment

	if [ -d $root_directory/etc/flash/predeployment ] ; then
		cd $root_directory/etc/flash
		$FIND predeployment -print | $CPIO -ocAO /tmp/flash.predeployment.$$.cpio 2> /tmp/cpout.$$
		if [ $? != 0 ] ; then
			$CAT /tmp/cpout.$$
			$RM /tmp/cpout.$$
			print_error_and_exit "$(gettext "CPIO error during archive creation.")"
		fi
	fi

	# converting predeployment archive into text

	$COMPRESS -f /tmp/flash.predeployment.$$.cpio
	$UUENCODE /tmp/flash.predeployment.$$.cpio.Z predeployment.cpio.Z
	$RM -f /tmp/flash.predeployment.$$.*
	echo "section_end=predeployment"

	# postdeployment customization script section

	echo "section_begin=postdeployment"

	# dynamic customer postdeployment scripts from $FLASH_DIR/postdeployment

	cd $FLASH_DIR
	$FIND postdeployment -print | $CPIO -ocO /tmp/flash.postdeployment.$$.cpio 2> /tmp/cpout.$$
	if [ $? != 0 ] ; then
		$CAT /tmp/cpout.$$
		$RM /tmp/cpout.$$
		print_error_and_exit "$(gettext "CPIO error during archive creation.")"
	fi

	# flash internal postdeployment script

	if [ -e $root_directory/usr/lib/flash/postdeployment_processing ] ; then
		cd $root_directory/usr/lib/flash
		echo postdeployment_processing | $CPIO -ocAO /tmp/flash.postdeployment.$$.cpio 2> /tmp/cpout.$$
		if [ $? != 0 ] ; then
			$CAT /tmp/cpout.$$
			$RM /tmp/cpout.$$
			print_error_and_exit "$(gettext "CPIO error during archive creation.")"
		fi
	fi

	# static customer postdeployment scripts from /etc/flash/postdeployment

	if [ -d $root_directory/etc/flash/postdeployment ] ; then
		cd $root_directory/etc/flash
		$FIND postdeployment -print | $CPIO -ocAO /tmp/flash.postdeployment.$$.cpio 2> /tmp/cpout.$$
		if [ $? != 0 ] ; then
			$CAT /tmp/cpout.$$
			$RM /tmp/cpout.$$
			print_error_and_exit "$(gettext "CPIO error during archive creation.")"
		fi
	fi

	# converting postdeployment archive into text

	$COMPRESS -f /tmp/flash.postdeployment.$$.cpio
	$UUENCODE /tmp/flash.postdeployment.$$.cpio.Z postdeployment.cpio.Z
	$RM -f /tmp/flash.postdeployment.$$.*
	echo "section_end=postdeployment"

	# reboot customization script section

	echo "section_begin=reboot"

	# dynamic customer reboot scripts from $FLASH_DIR/reboot

	cd $FLASH_DIR
	$FIND reboot -print | $CPIO -ocO /tmp/flash.reboot.$$.cpio 2> /tmp/cpout.$$
	if [ $? != 0 ] ; then
		$CAT /tmp/cpout.$$
		$RM /tmp/cpout.$$
		print_error_and_exit "$(gettext "CPIO error during archive creation.")"
	fi

	# flash internal reboot script

	if [ -e $root_directory/usr/lib/flash/reboot_processing ] ; then
		cd $root_directory/usr/lib/flash
		echo reboot_processing | $CPIO -ocAO /tmp/flash.reboot.$$.cpio 2> /tmp/cpout.$$
		if [ $? != 0 ] ; then
			$CAT /tmp/cpout.$$
			$RM /tmp/cpout.$$
			print_error_and_exit "$(gettext "CPIO error during archive creation.")"
		fi
	fi

	# static customer reboot scripts from /etc/flash/reboot

	if [ -d $root_directory/etc/flash/reboot ] ; then
		cd /etc/flash
		$FIND reboot -print | $CPIO -ocAO /tmp/flash.reboot.$$.cpio 2> /tmp/cpout.$$
		if [ $? != 0 ] ; then
			$CAT /tmp/cpout.$$
			$RM /tmp/cpout.$$
			print_error_and_exit "$(gettext "CPIO error during archive creation.")"
		fi
	fi

	# converting reboot archive into text

	$COMPRESS -f /tmp/flash.reboot.$$.cpio
	$UUENCODE /tmp/flash.reboot.$$.cpio.Z reboot.cpio.Z
	$RM -f /tmp/flash.reboot.$$.*
	echo "section_end=reboot"

	# summary section

	echo "section_begin=summary"
	${CAT}  $FLASH_DIR/summary
	echo "section_end=summary"

	# static customer sections from /etc/flash/sections

	if [ -d $root_directory/etc/flash/sections ] ; then
		cd $root_directory/etc/flash/sections
		/usr/bin/ls -1 | while read section; do
			if [ -d $section ] ; then
				echo "section_begin=$section"
				$FIND $section -print | $CPIO -oc > /tmp/flash.custom_section.$$.cpio 2> /tmp/cpout.$$
				if [ $? != 0 ] ; then
					$CAT /tmp/cpout.$$
					$RM /tmp/cpout.$$
					print_error_and_exit "$(gettext "CPIO error during archive creation.")"
				fi

				$COMPRESS -f /tmp/flash.custom_section.$$.cpio

				$UUENCODE /tmp/flash.custom_section.$$.cpio.Z $section.cpio.Z
				echo "section_end=$section"
				$RM -f /tmp/flash.custom_section.$$.cpio.Z /tmp/flash.custom_section.$$.cpio
			else
				echo "section_begin=$section"
				${CAT}  $section
				echo "section_end=$section"
			fi
		done
	fi

	# dynamic customer sections $FLASH_DIR/sections

	cd $FLASH_DIR/sections
	/usr/bin/ls -1 | while read section; do
		if [ -d $section ] ; then
			$FIND $section -print | $CPIO -oc > /tmp/flash.custom_section.$$.cpio 2> /tmp/cpout.$$
			if [ $? != 0 ] ; then
				$CAT /tmp/cpout.$$
				$RM /tmp/cpout.$$
				print_error_and_exit "$(gettext "CPIO error during archive creation.")"
			fi
			$COMPRESS -f /tmp/flash.custom_section.$$.cpio
			echo "section_begin=$section"
			$UUENCODE /tmp/flash.custom_section.$$.cpio $file.cpio.Z
			echo "section_end=$section"
			$RM -f /tmp/flash.custom_section.$$.cpio.Z /tmp/flash.custom_section.$$.cpio
		else
			echo "section_begin=$section"
			${CAT}  $section
			echo "section_end=$section"
		fi
	done

	# Write user-specified sections, if any
	for section in $section_list; do
		echo "section_begin=$section"
		${CAT}  $use_directory/$section
		echo "section_end=$section"
	done

	$RM -f /tmp/cpout.$$
}

#####################################################
# Function gen_archive files performs pipeline of
# cpio and perhaps compress, and perhaps computehash.
#####################################################

gen_archive_files()
{
	echo "section_begin=archive"

	if [[ $old_root_directory = "NON_DIFFERENTIAL" ]] ; then
		typeset gen_cmd="$FDO filter_dir $FILTER $root_directory | \
			${CPIO} -oc"
	else
		typeset gen_cmd="$FDO filter_dir $FILTER $root_directory | \
			$FDO $comparsion $root_directory $old_root_directory | \
			${CPIO} -oc"
	fi
	if [[ $generate_hash = $YES ]] ; then
	    gen_cmd="$gen_cmd | ${COMPUTEHASH} -f $hash_file"
	fi
	if [[ $compress_action = $YES ]] ; then
	    gen_cmd="$gen_cmd | compress -c"
        fi

	cd $root_directory

	eval ${gen_cmd}
	if [[ $? -eq 0 ]]; then
		return 0
	else
		return 1
	fi
}

#######################################################
# Function gen_archive performs the high-level control
# of flarcreate.
#######################################################

gen_archive()
{
	gen_ident_and_cookie

	gen_archive_files

	status=$?

	if [[ $status != 0 ]] ; then
		print_message "$(gettext "Unable to write archive file.")"
		return $status
	fi
}

#####################################
# Check that user is root
# (/usr/sbin/patchadd validate_uid())
#####################################

typeset -i uid
uid=$(${ID} | ${SED} 's/uid=\([0-9]*\)(.*/\1/')
if (( uid != 0 ))
then
	print_error_and_exit "$(gettext "You must be root to execute this script.")"
fi

#########################################################
# Miscellaneous intializations and beginning-of-job steps
#########################################################

current_dir=$(pwd)
NO="No"
YES="Yes"

# make sure required binaries exist
find_utils_or_exit

if [[ $# -lt 3 ]]; then
	print_usage_and_exit
fi

####################################################
# Initialize defaults and parse the invoking command
####################################################

content_author=
compress_action=$NO
creation_date=$(date -u '+''%Y''%m''%d''%H''%M''%S')
content_description_path=
use_directory=$PWD
creation_master=$(${UNAME} -n)
content_name=
tape_position=
tape_blocksize=
file_list=
exclusive_file_list=$NO
tape_block_default="64k"
sizing_action=$YES
generate_hash=$YES
hash_offset=0
hash_length=0
hash_file=
section_list=
new_keywords=
tape_usage=$NO
exclude_path=
content_description=
root_directory="/"
old_root_directory="NON_DIFFERENTIAL"
content_type=
archive_outfile=
getopt_error=$NO
FDO=/usr/lib/flash/fdo
DEBUG=0
QUIET=$YES
COMPUTEHASH=

comparsion=dir_compare
FILTER="/tmp/.flash_filter_one_.$$"
EXCLUSION_LIST="/usr/lib/flash/flash_exclusion_list"

# creation of Flash temporary directory structure

FLASH_DIR="/tmp/.flash.$$"
mkdir $FLASH_DIR
if [ $? != 0 ] ; then
	print_error_and_exit "$(gettext "Can not create temporary flash directory")"
fi
mkdir $FLASH_DIR/predeployment
if [ $? != 0 ] ; then
	$RM -rf $FLASH_DIR
	print_error_and_exit "$(gettext "Can not create temporary flash directory")"
fi
mkdir $FLASH_DIR/postdeployment
if [ $? != 0 ] ; then
	$RM -rf $FLASH_DIR
	print_error_and_exit "$(gettext "Can not create temporary flash directory")"
fi
mkdir $FLASH_DIR/reboot
if [ $? != 0 ] ; then
	$RM -rf $FLASH_DIR
	print_error_and_exit "$(gettext "Can not create temporary flash directory")"
fi
mkdir $FLASH_DIR/sections
if [ $? != 0 ] ; then
	$RM -rf $FLASH_DIR
	print_error_and_exit "$(gettext "Can not create temporary flash directory")"
fi
create_manifest=yes
integrity_check=yes

while getopts ":a:A:b:cCd:e:E:f:FHIi:m:Mn:p:qR:StT:u:U:vx:X:y:z:" opt; do
	case $opt in
		a  ) content_author=$OPTARG ;;
		A  ) old_root_directory=$OPTARG
		     echo "- $old_root_directory" >> $FILTER;;
		b  ) tape_blocksize=$OPTARG ;;
		c  ) compress_action=$YES ;;
		C  ) comparsion=full_dir_compare ;;
		d  ) use_directory=$OPTARG ;;
		e  ) content_description=$OPTARG ;;
		E  ) content_description_path=$OPTARG ;;
		f  ) $FDO do_file_list $OPTARG >> $FILTER ;;
		F  ) echo - / >> $FILTER ;;
		i  ) creation_date=$OPTARG ;;
		I  ) integrity_check=no ;;
		m  ) creation_master=$OPTARG ;;
		M  ) create_manifest=no ;;
		n  ) content_name=$OPTARG ;;
		H  ) generate_hash=$NO ;;
		p  ) tape_position=$OPTARG ;;
		q  ) QUIET=$YES ;;            # PRIVATE
		R  ) root_directory=$OPTARG ;;
		S  ) sizing_action=$NO ;;
		t  ) tape_usage=$YES ;;
		T  ) content_type=$OPTARG ;;
		u  ) section_list="$section_list $OPTARG" ;;
		U  ) new_keywords="$new_keywords $OPTARG" ;;
		v  ) DEBUG=1 ;;               # PRIVATE
		x  ) echo - $OPTARG >> $FILTER ;;
		X  ) $FDO do_x_list $OPTARG >> $FILTER ;;
		y  ) echo + $OPTARG >> $FILTER ;;
		z  ) cat $OPTARG >> $FILTER ;;
		\? ) print_error_and_usage "$(gettext "Option -%s is invalid.")" $OPTARG ;;
		\: ) print_error_and_usage "$(gettext "Option -%s has no value.")" $OPTARG ;;
		*  ) print usage and exit ;;
	esac
done

# find a valid computehash
if [ -x /usr/sbin/computehash ] ; then
    COMPUTEHASH=/usr/sbin/computehash
elif [ -x `dirname $0`/computehash ] ; then
    _pwd=$PWD
    cd `dirname $0`
    COMPUTEHASH=`pwd`/computehash
    cd $_pwd
else
    COMPUTEHASH=
fi

# Isolate outfile parameter - it should be the only argument left
shift $(($OPTIND - 1))
if [[ $# != 1 ]] ; then
	print_usage_and_exit
fi
archive_outfile=$1

###############################################
# Make format, dependency, and existence checks
###############################################

if [[ ! -d $root_directory ]] ; then
	print_error_and_usage "$(gettext "Directory %s does not exist or is not a directory.")" $root_directory
fi

if [[ $root_directory = ${root_directory#/} ]]; then
	print_error_and_usage "$(gettext "Root directory must have an absolute path.")"
fi

if [[ -z $content_name ]]; then
	print_error_and_usage "$(gettext 'Content name (option -n) must have a value.')"
fi
if [[ ${#creation_date} -ne 14  ]]; then
	print_error_and_usage "$(gettext "Creation date %s must be 14 digits long.")" $creation_date
fi
if [[ $creation_date != +([0-9]) ]]; then
	print_error_and_usage "$(gettext "Creation date %s must be numeric.")" $creation_date
fi
if [[ ! -z $content_description_path ]]; then
	if [[ ! -z $content_description  ]]; then
		print_error_and_usage "$(gettext "Options -E and -e are mutually exclusive.")"
	fi
	if [[ ! -r $content_description_path  ]]; then
		print_error_and_exit "$(gettext "Content description file %s is not available.")" $content_description_path
	fi
	content_description=$(< $content_description_path)
fi
if [[ $use_directory != $PWD  && -z $section_list ]]; then
	print_error_and_usage "$(gettext "Option -d is invalid in the absence of option -u.")"
fi
for section in $section_list; do
	if [[ ! -r $use_directory/$section ]]; then 
		print_error_and_exit "$(gettext "User section %s is not available.")" $use_directory/$section
	fi
done
if [[ ! -z $tape_position ]]; then
	if [[ $tape_usage = $NO ]]; then
		print_error_and_usage "$(gettext "Option -p is invalid in the absence of option -t.")"
	else
		# $tape_usage = $YES
		if [[ $tape_position != +([0-9]) ]]; then
			print_error_and_exit "$(gettext "Tape position %s must be a number.")" $tape_position
		fi
	fi
fi
if [[ ! -z $tape_blocksize && $tape_usage = $NO ]]; then
	print_error_and_usage "$(gettext "Option -b is invalid in the absence of option -t.")"
fi
if [[ $tape_usage = $YES ]]; then
	tape_blocksize=${tape_blocksize:-$tape_block_default}
	if [[ $tape_blocksize != +([0-9])?(@(k|b|w)) ]]; then
		print_error_and_exit "$(gettext "Tape blocksize %s must be number[k|b|w].")" $tape_blocksize
	fi
	if [[ $generate_hash = $YES ]]; then
	     print_message "$(gettext 'WARNING: hash generation disabled when using tape (-t)')"
	     generate_hash=$NO
	fi
fi
		
if [[ ! -z $exclude_path ]]; then
	if [[ ! -z "$root_directory" ]] ; then
		# make exclude dir relative to alternate root
		exclude_path=$root_directory/${exclude_path#/}
	fi
	if [[ ! -d $exclude_path ]]; then
		print_error_and_exit "$(gettext "Exclusion path %s is not a directory.")" $exclude_path
	else
		# Make relative exclude path absolute.  If we have an exclude
		# path AND an alternate root, this will never happen, as the
		# resulting exclude path will always be absolute after prepending
		# the alternate root.
		if [[ $exclude_path = ${exclude_path#/} ]]; then
			exclude_path=$(pwd)/$exclude_path
		fi		
	fi

	# collapse multiple /'s into a single /
	exclude_path=`echo $exclude_path | tr -s /`
	[[ $DEBUG -ge 1 ]] && echo "Using exclude path: $exclude_path"

	exclude_inode=$(${LS} -id $exclude_path |${AWK} '{print $1}')
fi

if [[ -z $archive_outfile ]]; then
	if [[ $tape_usage = $NO ]]; then
		print_error_and_usage "$(gettext "Path name for new archive must be provided.")"
	else
		print_error_and_usage "$(gettext "Tape drive name for new archive must be provided.")"
	fi
fi
if [[ $tape_usage = $NO ]]; then
	if [[ $archive_outfile = ${archive_outfile#/} ]]; then
		archive_outfile=$(pwd)/$archive_outfile
	fi
	if [[ -e $archive_outfile ]]; then
	${RM} -f $archive_outfile
	fi
	${TOUCH} $archive_outfile
	if [[ ! -w $archive_outfile ]]; then
		print_error_and_exit "$(gettext "Archive file %s is not writable.")" $archive_outfile
	fi
	read archive_inode junk <<-EOF
		$(${LS} -i $archive_outfile)
	EOF
fi

# append current directory if filelist is relative
if [[ -n "$file_list" ]] ; then
    if [[ $file_list = ${file_list#/} ]]; then
		file_list=$(pwd)/$file_list
    fi
fi

# we can't size the archive when doing a streamed file list, since
# we can only read the file list once.
if [[ "$file_list" = "-" && $sizing_action = $YES ]] ; then
    print_message "$(gettext "WARNING: Sizing not supported when using streamed file list")"
    sizing_action=$NO
fi
 
 
if [[ $old_root_directory = "NON_DIFFERENTIAL" ]] ; then
    FLASH_TYPE="FULL"
    print_message "$(gettext "Full Flash")"
else
    FLASH_TYPE="DIFFERENTIAL"
    FLASH_OLD_ROOT=$old_root_directory
    export FLASH_OLD_ROOT
    print_message "$(gettext "Differential Flash")"
fi

##############################################
# Determine what filesystems to archive, and
# build the archive pipelines
##############################################
start_dial

# Convert Relative path of archive file to Absolute Path
if [[ $tape_usage = $NO ]]; then
	for word in `echo $archive_outfile | tr "/" " "` ; do
		case $word in
			".")    ;;
			"..")   abs_archive_outfile=${abs_archive_outfile%/*} ;;
			*)      abs_archive_outfile=${abs_archive_outfile}/${word} ;;
		esac
	done

	 archive_outfile=$abs_archive_outfile
fi

# Exclude the archive file if we're not using tape and the archive
# file is on this filesystem

echo - /${archive_outfile#${root_directory}} >> $FILTER

if [ $integrity_check = yes ] ; then
	# check package integrity
        print_message "$(gettext "Checking integrity...")"
	$FDO integrity_check $FILTER ${root_directory}/var/sadm/install/contents
	if [ $? != 0 ]; then
		print_error_and_exit "$(gettext "Integrity check failed.")"
	fi
        print_message "$(gettext "Integrity OK.")"
else
        print_message "$(gettext "No integrity check. Option \"-I\" set.")"
fi

# Strippin non local filesystems out ou flash scope

(cat /etc/vfstab;echo mnttab;cat /etc/mnttab) | $FDO mountpoints_to_filter ${root_directory} >> $FILTER

# excluding rewmovable devices

echo ". /cdrom" >> $FILTER
echo ". /floppy" >> $FILTER

if [[ $old_root_directory != "NON_DIFFERENTIAL" ]] ; then
#	echo ". /devices" >> $FILTER
#	echo "+ /devices/pseudo" >> $FILTER
#	echo "- /dev/dsk" >> $FILTER
#	echo "- /dev/rdsk" >> $FILTER
#	echo "- /dev/fbs" >> $FILTER
#	echo "- /dev/rmt" >> $FILTER
#	echo "- /dev/cfg" >> $FILTER 
#	echo "- /dev/dump" >> $FILTER
#	echo "- /dev/cua" >> $FILTER
#	echo "- /dev/fd" >> $FILTER
#	echo "- /dev/swap" >> $FILTER
#	echo "- /dev/term" >> $FILTER
#	echo "- /dev/pts" >> $FILTER
#else
	echo ". /devices" >> $FILTER
	echo ". /dev" >> $FILTER
	while read fpattern ; do
		echo "- $fpattern" >> $FILTER
		flist=`ls ${fpattern} 2> /dev/null`
		# we don't include files that aren't on the system
		if [ $? = 0 ] ; then
			for i in ${flist} ; do
				if [ $i = $fpattern ] ; then
					echo "- $i" >> $FILTER
				fi
			done
		fi
	done < $EXCLUSION_LIST
fi

echo "- /tmp/flash_tmp" >> $FILTER
echo "+ /kernel/drv/st.conf" >> $FILTER

# excluding volitile files
#

$FDO sort_list $root_directory $FILTER > /tmp/.flash_filter_two_.$$

rm -f $FILTER
FILTER="/tmp/.flash_filter_two_.$$"

# If we're using an exclude path and it's on this filesystem,
# exclude it

stop_dial

#environment for precreation customer scripts

export FLCHECK="$FDO check_name $FILTER "
export FLASH_DIR
export FLASH_ROOT=$root_directory
export FLASH_ARCHIVE=$archive_outfile
export FLASH_DATE=$creation_date
export FLASH_MASTER=$creation_master
export FLASH_NAME=$content_name
export FLASH_TYPE

#first record in summary

echo "flash creation started" > $FLASH_DIR/summary
date >> $FLASH_DIR/summary

#exec precreation customer scripts

print_message "$(gettext "Running precreation scripts...")"

$FDO dir_exec $root_directory/etc/flash/precreation
if [ $? != 0 ]; then
	print_error_and_exit "$(gettext "Precreation script failure.")"
fi

print_message "$(gettext "Precreation scripts done.")"

##########################################
# If asked, find out size of archive-to-be
##########################################

if [[ $sizing_action = $YES ]]; then
	size_archive
fi

######################################
# Position magnetic tape, if requested
######################################

if [[ $tape_usage = $YES && ! -z $tape_position ]]; then
	print_message "$(gettext "Positioning tape drive...")"
	start_dial

	${MT} -f $archive_outfile asf $tape_position
	if [[ $? -gt 0 ]]; then
		print_error_and_exit "$(gettext "Unable to move tape %s to position %d.")" $archive_outfile $tape_position
	fi
	stop_dial
fi

###################
# Write the archive
###################

print_message "$(gettext "Creating the archive...")"

start_dial

# Use output redirection for disk, dd for tape
if [[ $tape_usage = $NO ]]; then
	gen_archive > $archive_outfile
else
	gen_archive | ${DD} of=$archive_outfile obs=$tape_blocksize 2>/dev/null
fi
status=$?

# add hash, if we computed one.  lets hope the hash goes near the
# beginning of the file or the seek will take forever with a blocksize of 1.
if [[ $generate_hash = $YES ]] ; then
    if [ -r $hash_file -a -f $hash_file ] ; then
	${DD} if=$hash_file of=$archive_outfile bs=1 count=$hash_length \
	    seek=$hash_offset conv=notrunc >/dev/null 2>&1
	${RM} -f $hash_file
    else
	print_error_and_exit "$(gettext "Could not generate hash for %s")" $archive_outfile
    fi
fi


stop_dial

if [[ $status != 0 ]] ; then
	print_error_and_exit "$(gettext "Unable to write archive.")"
fi

#########################################
# Perform end-of-job processing, and exit
#########################################

rm $FILTER

print_message "$(gettext "Archive creation complete.")"
exit 0
