Blob Blame History Raw
#!/bin/sh

# srcdist.rawball: extract and repackage a subset of unmodified source files
# from a known upstream source distribution tarball, along with a manifest.

# this file is covered by COPYING.SRCDIST.

set -eu

mb_ruledir=
mb_rawball=
mb_tarball=
mb_tarball_sha256=

mb_script="${0}"
mb_status=1
mb_manifest=MANIFEST.rawball

export LC_ALL=C

rawball_usage()
{
	printf 'usage: %s\n' "$mb_script" >&2
	printf '\t%s\n' \
		'--ruledir=/path/to/rule/dir'           \
		'--tarball=/path/to/upstream.tar.xz'    \
		'--tarball-sha256=upstream-signature'   \
		'--rawball=output-tarball-name'         \
		>&2

	printf '\nThis will extract and repackage a subset of unmodified source\n' >&2
	printf '  files from a known upstream source distribution tarball,\n' >&2
	printf '  along with a manifest.\n\n' >&2

	printf '\nThe --ruledir argument should point to a directory ' >&2
	printf 'containing the following files:\n' >&2
	printf '  upstream.sha256.known\n' >&2
	printf '  rawball.include.patterns  (appropriate for pax)\n' >&2
	printf '  rawball.exclude.patterns  (appropriate for grep -v -f)\n\n' >&2

	exit ${mb_status}
}

for arg ; do
	case "$arg" in
		--ruledir=*)
			mb_ruledir=${arg#*=}
			;;

		--rawball=*)
			mb_rawball=${arg#*=}
			;;

		--tarball=*)
			mb_tarball=${arg#*=}
			;;

		--tarball-sha256=*)
			mb_tarball_sha256=${arg#*=}
			;;

		*)
			printf '\n*** %s: unsupported argument!' "$mb_script" >&2
			printf '\n*** %s\n' "${arg#}" >&2
			exit 2
	esac
done

rawball_ruledir_error()
{
	mb_status=2

	printf '\n*** %s: a required file in %s is missing!\n\n' \
		"$mb_script" "$mb_ruledir" >&2

	rawball_usage
}

rawball_init_vars()
{
	export LC_ALL='C'

	if [ -z ${mb_ruledir:-} ]; then
		rawball_usage
	fi


	if [ -z ${mb_rawball:-} ] ||  [ -z ${mb_tarball:-} ] ||  [ -z ${mb_tarball_sha256:-} ]; then
		rawball_usage
	fi


	eval mb_ruledir=$(printf '%s' "$mb_ruledir")
	eval mb_tarball=$(printf '%s' "$mb_tarball")


	stat "$mb_ruledir/upstream.sha256.known"    > /dev/null || rawball_ruledir_error
	stat "$mb_ruledir/rawball.include.patterns" > /dev/null || rawball_ruledir_error
	stat "$mb_ruledir/rawball.exclude.patterns" > /dev/null || rawball_ruledir_error


	mb_known_sha256=$(grep "$mb_tarball_sha256" "${mb_ruledir}/upstream.sha256.known" || true)
	mb_known_sha256="${mb_known_sha256%% *}"

	if [ "$mb_known_sha256" != "$mb_tarball_sha256" ]; then
		printf '\n*** %s: %s is not a known sha-256 signature!\n\n' \
			"$mb_script" "$mb_tarball_sha256" >&2
		exit 2
	fi
}

rawball_verify_sha256_signature()
{
	mb_tarball_sha256_test=$(sha256sum "$mb_tarball")
	mb_tarball_sha256_test="${mb_tarball_sha256_test%% *}"

	if [ "$mb_tarball_sha256_test" != "$mb_tarball_sha256" ]; then
		printf '\n*** %s: sha-256 signature does not match!\n\n' "$mb_script" >&2
		exit 2
	fi

}

rawball_extract_upstream_tarball()
{
	mb_rawball_files=$(xz -d -c -f "$mb_tarball"                \
		| pax $(cat "$mb_ruledir/rawball.include.patterns")  \
		| grep -v -f "${mb_ruledir}/rawball.exclude.patterns" \
		| sort)

	mb_topdir=$(printf '%s\n' ${mb_rawball_files} | sed -n 1p)
	mb_topdir=${mb_topdir%%/*}
	mb_rawdir=${mb_topdir}.raw

	if [ -d ${mb_rawdir} ]; then
		printf '\n*** %s: the directory `%s already exists!\n\n' \
			"$mb_script" "${mb_rawdir}'" >&2
		exit 2
	fi

	mkdir ${mb_rawdir}

	xz -d -c -f "$mb_tarball" | pax -d -r -s "/^${mb_topdir}/${mb_rawdir}/" ${mb_rawball_files}

	mb_packed=$(find ${mb_rawdir} -type f | sort)
	mb_refobj=$(find ${mb_rawdir} -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f 2- | tail -n 1)
	mb_status=$(cd -- ${mb_rawdir}; sha256sum $(find . -type f | sort) > ${mb_manifest})

	touch -a -c -m -r ${mb_refobj} $(find ${mb_rawdir} -type d)
	touch -a -c -m -r ${mb_refobj} ${mb_rawdir}/${mb_manifest}
	touch -a -c -m -r ${mb_refobj} ${mb_rawdir}
}

rawball_create_downstream_rawball()
{
	pax -w -x tar ${mb_packed} ${mb_rawdir}/${mb_manifest} | xz -c > "$mb_rawball"
}

# init variables and verify arguments
rawball_init_vars

# validate input
rawball_verify_sha256_signature

# extract tarball (top-level directory must not exist)
rawball_extract_upstream_tarball

# create downstream rawball of unmodified source files
rawball_create_downstream_rawball

# all done
exit 0