From 349e272f641c58998c67bda8d6b381ca4449ed63 Mon Sep 17 00:00:00 2001 From: midipix Date: Jan 22 2020 11:35:49 +0000 Subject: srcdist.rawball: initial implementation. --- diff --git a/bin/srcdist.rawball b/bin/srcdist.rawball new file mode 100755 index 0000000..5df09ea --- /dev/null +++ b/bin/srcdist.rawball @@ -0,0 +1,165 @@ +#!/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 + +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 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() +{ + 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) > MANIFEST.RAWBALL) + + touch -a -c -m -r ${mb_refobj} $(find ${mb_rawdir} -type d) + touch -a -c -m -r ${mb_refobj} ${mb_rawdir}/MANIFEST.RAWBALL + touch -a -c -m -r ${mb_refobj} ${mb_rawdir} +} + +rawball_create_downstream_rawball() +{ + pax -w -x tar ${mb_packed} ${mb_rawdir}/MANIFEST.RAWBALL | 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