#!/bin/sh
#
# $NetBSD: checksum,v 1.13.2.1 2013/02/13 21:33:31 spz Exp $
#
# Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by Johnny C. Lam.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
#        This product includes software developed by the NetBSD
#        Foundation, Inc. and its contributors.
# 4. Neither the name of The NetBSD Foundation nor the names of its
#    contributors may be used to endorse or promote products derived
#    from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#

######################################################################
#
# NAME
#	checksum -- checksum files
#
# SYNOPSIS
#	checksum [options] distinfo [file ...]
#
# DESCRIPTION
#	checksum will verify the checksums in the distinfo file for each
#	of the files specified.
#
#	The checksum utility exits with one of the following values:
#
#	0	All of the file checksums verify.
#
#	1	At least one of the file checksums did not match.
#
#	2	At least one of the files is missing any checksum.
#
#	>2	An error occurred.
#
# OPTIONS
#	-a algorithm	Only verify checksums for the specified algorithm.
#
#	-p		The specified files are patches, so strip out any
#			lines containing NetBSD RCS ID tags before
#			computing the checksums for verification.
#
#	-s suffix	Strip the specified suffix from the file names
#			when searching for the checksum.
#
######################################################################

set -e		# exit on errors

: ${DIGEST:=digest}
: ${CAT:=cat}
: ${ECHO:=echo}
: ${SED:=sed}
: ${TEST:=test}

# Work around problematic UTF-8 handling in "sed" under Mac OS X Mountain Lion.
LC_ALL=C; export LC_ALL

self="${0##*/}"

usage() {
	${ECHO} 1>&2 "usage: $self [-a algorithm] [-p] [-s suffix] distinfo [file ...]"
}

# Process optional arguments
algorithm=
patch=
suffix=
while ${TEST} $# -gt 0; do
	case "$1" in
	-a)	algorithm="$2"; shift 2 ;;
	-p)	patch=yes; shift ;;
	-s)	suffix="$2"; shift 2 ;;
	--)	shift; break ;;
	-*)	${ECHO} 1>&2 "$self: unknown option -- ${1#-}"
		usage
		exit 128
		;;
	*)	break ;;
	esac
done

# Process required arguments
${TEST} $# -gt 0 || { usage; exit 128; }
distinfo="$1"; shift
files="$@"
files_left="$@"

if ${TEST} ! -f "$distinfo"; then
	${ECHO} 1>&2 "$self: distinfo file missing: $distinfo"
	exit 128
fi

digestcmd=
case "${DIGEST}" in
/*)
	if ${TEST} -x "${DIGEST}"; then
		digestcmd="${DIGEST}"
	fi
	;;
*)
	SAVEIFS="$IFS"; IFS=:
	for i in $PATH; do
		if ${TEST} -x "$i/${DIGEST}"; then
			digestcmd="$i/${DIGEST}"
			break
		fi
	done
	IFS="$SAVEIFS"
	;;
esac

if ${TEST} -z "$digestcmd"; then
	${ECHO} 1>&2 "$self: \`\`${DIGEST}'' is missing"
	exit 128
fi

{ exitcode=0
  while read d_alg d_file d_equals d_checksum; do
	case "$d_alg" in
	"#"*)	continue ;;	# skip comments
	"\$"*)	continue ;;	# skip RCS ID
	"")	continue ;;	# skip empty lines
	Size)	continue ;;	# skip lines holding filesizes, not checksums
	esac

	if ${TEST} -n "$algorithm"; then
		${TEST} "$d_alg" = "$algorithm" || continue
	fi

	for file in $files; do
		sfile="${file%$suffix}"
		${TEST} -z "$patch" || sfile="${sfile##*/}"
		${TEST} "$d_file" = "($sfile)" || continue

		new_files_left=
		for file_left in $files_left; do
			${TEST} "${file_left}" = "${file}" || \
			    new_files_left="${new_files_left} ${file_left}"
		done
		files_left="${new_files_left}"

		if ${TEST} "$d_checksum" = "IGNORE"; then
			${ECHO} 1>&2 "$self: Ignoring checksum for $sfile"
			continue
		fi
		if ${TEST} ! -f $file; then
			${ECHO} 1>&2 "$self: $file does not exist"
			exit 128
		fi
		if ${TEST} -z "$patch"; then
			checksum=`${DIGEST} $d_alg < $file`
		else
			checksum=`${SED} -e '/[$]NetBSD.*/d' $file | ${DIGEST} $d_alg`
		fi
		if ${TEST} "$d_checksum" = "$checksum"; then
			${ECHO} "=> Checksum $d_alg OK for $sfile"
		else
			${ECHO} 1>&2 "$self: Checksum $d_alg mismatch for $sfile"
			exit 1
		fi
		break
	done
  done
  if ${TEST} -n "$files_left"; then
	for file in $files_left; do
		if ${TEST} -n "$algorithm"; then
			${ECHO} 1>&2 "$self: No $algorithm checksum recorded for $file"
		else
			${ECHO} 1>&2 "$self: No checksum recorded for $file"
		fi
		exitcode=2
	done
  fi
  exit $exitcode; } < $distinfo
