diff --git a/scripts/pkgmeek b/scripts/pkgmeek index 7d0b869..a5b129a 100755 --- a/scripts/pkgmeek +++ b/scripts/pkgmeek @@ -20,7 +20,7 @@ if [ "$PKGMK_CLEAN" = "yes" ]; then [ "$PKGMK_REFRESH_SIG" = "yes" ] && refresh_signature [ "$o_ignored" = "" ] || { warning "option -c nullifies these requested options:"; echo "$o_ignored"; } - exec $PRTWASH_COMMAND -p -s "$(pwd)" + exec $PRTWASH_COMMAND -p -s -q "$(pwd)" fi # # Read the Pkgfile to determine what to do next. But first ensure that @@ -64,11 +64,11 @@ done [ -w "$(dirname "$work")" ] || work="$(pwd)"/work rm -rf "$work"; mkdir -p "$work"/{src,pkg} && cd "$work" -for (( u=0; u<${#_local_[@]}; u++ )); do - here="${_local_[$u]}" - url="${source[$u]}" - # at least one of the following commands should put a file of the - # appropriate name in the current directory +# Skip the retrieval of sources if the user only asked for '-utd' +[ "$PKGMK_MTIME_ONLY" = "yes" ] || { errDL=0; for (( u=0; u<${#_local_[@]}; u++ )); do + here="${_local_[$u]}"; url="${source[$u]}" +# at least one of the following commands should put a file of the +# appropriate name in the current directory [ -e "$here" ] || [ "$src_dir" = "" ] || [ ! -e "$src_dir/$here" ] || ln -sf "$src_dir/$here" . [ -e "$here" ] || [ ! -e "$PKGMK_ROOT/$here" ] || ln -sf "$PKGMK_ROOT/$here" . [ -e "$here" ] || [[ $url =~ ^(https|ssh|git)://.*/(.+)\.git ]] || { @@ -80,22 +80,25 @@ for (( u=0; u<${#_local_[@]}; u++ )); do # but if not, exit with an informative error message if [ ! -e "$here" ]; then error "failed to download $here. Check connection and try again." - errDL=$E_DOWNLOAD + errDL+=1 fi -done +done; } -{ [ "$PKGMK_DOWNLOAD_ONLY" = "yes" ] || [ "$errDL" ]; } && exit $errDL - -# Now that all the files are on disk, check mtimes to determine whether a build is needed. +# If the user only asked for '-utd', perform the check using the sources that do exist. check_pkg_mtime && pkg_ood=0 || pkg_ood=1 [ "$PKGMK_MTIME_ONLY" = "no" ] || exit $pkg_ood + +# If the user did NOT ask for '-utd' or '-do', then all sources must be present. +{ [ "$PKGMK_DOWNLOAD_ONLY" = "yes" ] || [ "$errDL" ] ; } && exit $(( E_DOWNLOAD*(errDL>0) )) + +# Some further tests before proceeding with the build [ "$pkg_ood" = 1 ] || [ "$PKGMK_FORCE" = "yes" ] || [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ] || \ - [ "$PKGMK_UPDATE_SIG" = "yes" ] || exit 0 +[ "$PKGMK_UPDATE_SIG" = "yes" ] || [ "$PKGMK_UPDATE_MD5" = "yes" ] || exit 0 [ "$PKGMK_CHECK_SIG" = "yes" ] || echo "Checking signatures before unpacking..." -# The option -uf is meant to be used after a previous invocation of pkgmk has -# alerted the user to a footprint mismatch. The option -us is likewise meant -# to update the signature, which only requires the sources and the footprint. +# The option -uf is meant to be used AFTER a previous invocation of pkgmeek has +# alerted the user to a footprint mismatch. The options -us|-um are likewise meant +# to update the signature|md5sum, which only requires the sources and the footprint. if [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ]; then [ -f "$package" ] || \ { error "unable to update footprint. File '$package' not found."; @@ -103,25 +106,33 @@ if [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ]; then [ "$pkg_ood" = 0 ] || [ "$PKGMK_FORCE" = "yes" ] || \ { error "outdated package. Use '-f' to force the footprint update."; exit "$E_FOOTPRINT"; } - make_manifest "footprint" > "$PKGMK_ROOT/.footprint" || \ + cat_manifest footprint > "$PKGMK_ROOT/.footprint" || \ { error "Failed to write the footprint."; exit "$E_DIRPERM"; } fi -if [ "$PKGMK_UPDATE_SIG" = "yes" ]; then - make_signature > "$PKGMK_ROOT/.signature" || - { error "Failed to update signature."; exit "$E_DIRPERM"; } -fi -if [ "$PKGMK_UPDATE_SIG" = "yes" ] || [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ]; +[ "$PKGMK_UPDATE_SIG" = "no" ] || \ + { cat_signature > "$PKGMK_ROOT/.signature" && + echo "Signature successfully created."; } || \ + { cat_manifest md5sum > "$PKGMK_ROOT"/.md5sum && + warning "Signature creation failed, falling back to md5sums."; } \ + || { info "Could not create signatures or md5sums."; exit "$E_DIRPERM"; } +[ "$PKGMK_UPDATE_MD5" = "no" ] || \ + cat_manifest md5sum >"$PKGMK_ROOT"/.md5sum || \ + { info "Could not create requested md5sums."; exit "$E_DIRPERM"; } +# Exit after fulfilling any *explicit* requests for (signed) manifests +# (decision regarding the work directory is retained from the first run of pkgmeek) +if [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ] || [ "$PKGMK_UPDATE_SIG" = "yes" ] || \ + [ "$PKGMK_UPDATE_MD5" = "yes" ]; then exit 0 fi # All the sources should be here by now, let's verify that we can trust them. -readonly cs_fail_msg="Use '--ignore-signature' to override, if you have determined their integrity by other means." -check_signature "pre-build" | parse_signify_output +readonly cs_fail_msg="Use '--ignore-signature' to override, if you have determined integrity by other means." +[ "$PKGMK_IGNORE_SIG" = "yes" ] || { check_signature "pre-build" | parse_signify_output; case $? in 0) info "Sources successfully authenticated." ;; 1) error "Signature file missing or corrupted." ; echo "$cs_fail_msg" ;; 2) error "Failed to authenticate remote sources using signify." ; echo "$cs_fail_msg" ;; -esac +esac; } [ "$PKGMK_CHECK_SIG" = "no" ] || exit 0 # no need to continue if the user only requested -cs # What used to be called unpack_source() is now hard-coded into the main routine. @@ -168,45 +179,23 @@ else error "Unable to create the compressed package $package." exit $E_DIRPERM fi + +# Ensure that $work/ contains the package or a symlink to it, then check the footprint [ "$pkg_dir" = "$(pwd)/" ] || ln -sf "$pkg_dir$package" . +[ "$PKGMK_IGNORE_FOOTPRINT" = "yes" ] || check_manifest footprint || exit $E_MANIFEST -# The $work directory now has a symlink to the package, so check its footprint -if ! check_manifest "footprint" ; then - [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ] && make_manifest "footprint" > "$PKGMK_ROOT"/.footprint - [ "$PKGMK_IGNORE_FOOTPRINT" = "no" ] && exit $E_MANIFEST -fi - -# Fulfill any *explicit* requests for (signed) manifests, then exit -# (disposal of the work directory is retained from the first run of pkgmeek) -[ -f "$PKGMK_ROOT/.signature" ] || [ "$PKGMK_UPDATE_SIG" = "no" ] || \ - warning "Signature not found, creating new." -[ "$PKGMK_UPDATE_SIG" = "no" ] || \ - { make_signature > "$PKGMK_ROOT/.signature" && - echo "Signature successfully created."; } || \ - { make_manifest "md5sum" > "$PKGMK_ROOT"/.md5sum && - warning "Signature creation failed, falling back to md5sums."; } \ - || { info "Could not create signatures or md5sums."; exit "$E_DIRPERM"; } -[ "$PKGMK_UPDATE_MD5" = "no" ] || \ - make_manifest "md5sum" >"$PKGMK_ROOT"/.md5sum || \ - { info "Could not create requested md5sums."; exit "$E_DIRPERM"; } -if [ "$PKGMK_UPDATE_SIG" = "yes" ] || [ "$PKGMK_UPDATE_MD5" = "yes" ]; then - exit 0 -fi - -# Clean up, part 1 +# Clean up, part 1: remove soft links and the {src,pkg} trees +find . -maxdepth 1 -mindepth 1 -type l -delete [ "$PKGMK_KEEP_WORK" = "yes" ] || rm -rf src pkg # Install if requested # First find out how the effective user will invoke pkgadd -case $UID in - 0) SUDO="" ;; - *) SUDO="sudo " ;; -esac -[ -z "$SUDO" ] || [ -x $(command -v "$SUDO") ] || SUDO="/usr/bin/doas " -[ -x $(command -v "$SUDO") ] || SUDO="su -c" +[ $UID = 0 ] || PKGMK_SU="sudo "; +[ -z "$PKGMK_SU" ] || [ -x $(command -v "$PKGMK_SU") ] || PKGMK_SU="/usr/bin/doas "; +[ -x $(command -v "$PKGMK_SU") ] || PKGMK_SU="su -c"; if [ "$PKGMK_INSTALL_COMMAND" ]; then - if ! $SUDO $PKGMK_INSTALL_COMMAND "$package"; then + if ! $PKGMK_SU $PKGMK_INSTALL_COMMAND "$package"; then error "Unable to install $package using pkgadd." exit $E_INSTALL fi @@ -263,10 +252,13 @@ PKGMK_NOSTRIP=".nostrip" ######################## subroutines ################################ parse_options() { + ARGV=( "$@" ) # retain all arguments in case '-r' was not the first while [ "$1" ]; do case $1 in - -r|--recursive) recursive "$@" ;; - -c|--clean) PKGMK_CLEAN="yes" ;; + -r|--recursive) recursive "$ARGV" ;; + -c|--clean) [ -x "$PRTWASH_COMMAND" ] && PKGMK_CLEAN="yes" || \ + { error "option '-c' not supported ($PRTWASH_COMMAND not installed)"; + exit 1; } ;; -uf|--update-footprint) PKGMK_UPDATE_FOOTPRINT="yes" ;; -um|--update-md5sum) PKGMK_UPDATE_MD5="yes" ;; -us|--update-signature) PKGMK_UPDATE_SIG="yes" ;; @@ -330,15 +322,15 @@ print_help() { echo " -u, --upgrade build and install package (as upgrade)" echo " -do, --download-only stop after downloading all the necessary source file(s)" echo " -eo, --extract-only stop after downloading and extracting source file(s)" - echo " -utd, --up-to-date check whether the built package is up to date, then exit" - echo " -uf, --update-footprint update footprint using result from last build" + echo " -utd, --up-to-date report whether the built package is up to date, then exit" + echo " -um, --update-md5sum update md5sum of the downloaded sources, do not build" + echo " -us, --update-signature update signature of Pkgfile and sources, do not build" + echo " -cs, --check-signature verify the signatures, do not build" echo " -if, --ignore-footprint build package without checking footprint" echo " -in, --ignore-new build package, ignoring new files in a footprint mismatch" - echo " -um, --update-md5sum update md5sum" echo " -im, --ignore-md5sum build package without checking md5sum" - echo " -cs, --check-signature verify the signatures, do not proceed with the build" - echo " -us, --update-signature update signatures only, do not proceed with the build" - echo " -is, --ignore-signature build package without checking the signature" + echo " -is, --ignore-signature build package without checking signature" + echo " -uf, --update-footprint update footprint using result from last build" echo " -rs, --refresh-signature create new signature and keep existing sha256 checksums" echo " -sk, --secret-key use to sign the port" echo " -pk, --public-key check the port signature using public-key " @@ -351,7 +343,7 @@ print_help() { } validate_pkgfile() { # called from within PKGMK_ROOT - local errcode nn nv nr nb + local errcode nn nv nr nb checksum absent check_signature "pre-Pkgfile" | parse_signify_output errcode=$? [ "$errcode" = 0 ] || info "Use '-is' if you have confirmed its origin some other way." @@ -361,28 +353,17 @@ validate_pkgfile() { # called from within PKGMK_ROOT # and in the later build, but to be safe we use a nested subshell ( . Pkgfile; [ -n "$name" ] || nn=1; [ -n "$version" ] || nv=1; \ [ -n "$release" ] || nr=1; [ "$(type -t build)" = "function" ] || nb=1; \ - echo $(( nn+2*nv+4*nr+8*nb )) ) | check_required_vars + echo $(( nn+2*nv+4*nr+8*nb )) ) | { read -r checksum; + [ $((checksum & 1)) = 1 ] && absent=" 'name'"; + [ $((checksum & 2)) = 2 ] && absent+=" 'version'"; + [ $((checksum & 4)) = 4 ] && absent+=" 'release'"; + [ $((checksum & 8)) = 8 ] && absent+=" 'build()'"; + [ "$checksum" = 0 ] || + { error "Pkgfile does not specify these required variables:"; + info "$absent"; exit "$E_PKGFILE"; }; } } -check_required_vars() { - local checksum absent v - read -r checksum - - [ $((checksum & 1)) = 1 ] && absent=("'name'") - [ $((checksum & 2)) = 2 ] && absent=("${absent[@]}" "'version'") - [ $((checksum & 4)) = 4 ] && absent=("${absent[@]}" "'release'") - [ $((checksum & 8)) = 8 ] && absent=("${absent[@]}" "'build()'") - - if [ "$checksum" -gt 0 ]; then - error "Pkgfile does not specify these required variables:" - for v in "${absent[@]}"; do - echo -n "$v " - done - echo; exit $E_PKGFILE - fi -} - -check_pkg_mtime() { # only called before a build attempt, not again after a successful build +check_pkg_mtime() { # can be called even if some sources are missing local status=1; local li=0; local pkg_ood="yes" if [ -f "$package" ]; then @@ -402,7 +383,7 @@ check_pkg_mtime() { # only called before a build attempt, not again after a succ return $status } -make_manifest() { +cat_manifest() { case "$1" in footprint) pkginfo --footprint "$package" \ @@ -420,12 +401,12 @@ make_manifest() { check_manifest() { local FILTER TRUTH CN CM local FILE="$1.tmp"; local retval=0 - [ ! -f "$package" ] && { error "$package not found. Cannot check $1."; + [ -f "$package" ] || [ "$1" = "md5sum" ] || { error "$package not found. Cannot check $1."; return "$E_MANIFEST"; } [ "$1" = "md5sum" ] && FILTER="| sort -k 3" || FILTER="" TRUTH="$PKGMK_ROOT/.$1" - make_manifest $1 $FILTER > "$FILE" + cat_manifest $1 $FILTER > "$FILE" if [ -f "$TRUTH" ]; then cat "$TRUTH" $FILTER > "${FILE%tmp}orig" diff -w -t -U 0 <(sort "${FILE%tmp}orig") <(sort "${FILE}") | \ @@ -455,11 +436,14 @@ parse_signify_output() { # chomps the output of check_signature() [ "$PKGMK_IGNORE_SIG" = "yes" ] && return 0 while read -r signout; do case "$signout" in + *"Pkgfile verification failed") + signerr=-1; error "Signature missing! Unable to authenticate the Pkgfile." + ;; *"verification failed") - signerr=1; echo "Signature file corrupted or unreadable." + signerr=1; error "Signature file corrupted or unreadable." ;; *"FAIL") - signerr=2; echo "Signature mismatch found:" + signerr=2; error "Signature mismatch found:" echo "$signout" | awk -F: '/FAIL/ {printf "MISMATCH %s\n", $1}' ;; esac @@ -467,13 +451,13 @@ parse_signify_output() { # chomps the output of check_signature() return $signerr } -check_signature() { - # called from within the src subdir unless "when"="pre-Pkgfile". - # Pass control to check_manifest() if the signature is missing and - # "ignore-md5" has not been requested. +check_signature() { # called from $PKGMK_ROOT in the case "when"="pre-Pkgfile", + # otherwise called from within $work. Pass control to + # check_manifest() if the signature is missing and "ignore-md5" + # has not been requested. local reqfiles s local when="$1" - [ "$PKGMK_IGNORE_SIG" = "yes" ] && echo; return + if [ -f "$PKGMK_ROOT/.signature" ]; then [ "$when" = "pre-Pkgfile" ] && reqfiles=(Pkgfile) || reqfiles=(.footprint) @@ -493,15 +477,14 @@ check_signature() { "${reqfiles[@]}" 2>&1 fi else + [ "$when" != "pre-Pkgfile" ] || echo "Pkgfile verification failed" [ "$when" = "pre-Pkgfile" ] || [ "$PKGMK_IGNORE_MD5" = "yes" ] || \ { info "Signature not found, falling back to old md5sum checking."; - check_manifest "md5sum" ; } + check_manifest md5sum ; } fi - # remove soft links - [ "$when" = "post-build" ] && find . -maxdepth 1 -mindepth 1 -type l -delete } -make_signature() { +cat_signature() { for key in ~/.ssh/*.sec /etc/ports/*.sec; do [[ -e "$key" ]] || continue # workaround for brain-dead shell globbing pub=/etc/ports/$(basename "${key/%.sec/.pub}") @@ -520,8 +503,7 @@ make_signature() { refresh_signature() { if [ -e ".signature" ] && [ ! -w ".signature" ]; then - echo "error: .signature not writable." - return $E_SIGNATURE + echo "error: .signature not writable."; return $E_DIRPERM fi local REPO @@ -540,8 +522,8 @@ refresh_signature() { recursive() { local ARGS FILE DIR - [ "$PKGMK_CLEAN" == "no" ] || { find "$PKGMK_ROOT" -name Pkgfile \ - -printf "%h\n" | xargs "$PRTWASH_COMMAND" -s -p -b ; exit $? ; } + [ "$PKGMK_CLEAN" == "no" ] || { find "$PKGMK_ROOT" -name Pkgfile -printf "%h\n" \ + | xargs "$PRTWASH_COMMAND" -s -p -b -q; exit $? ; } ARGS=$(echo "$@" | sed -e "s/--recursive//g; s/[ ]+-r[ ]+/ /g") for FILE in $(find "$PKGMK_ROOT" -name Pkgfile | sort); do @@ -568,8 +550,8 @@ error() { ######################## end of subroutines ########################### ## Now ensure that they cannot be overwritten when sourcing Pkgfile ## -readonly -f main parse_options print_help validate_pkgfile check_required_vars \ - check_pkg_mtime make_manifest check_manifest check_signature make_signature \ +readonly -f main parse_options print_help validate_pkgfile check_pkg_mtime \ + cat_manifest check_manifest cat_signature check_signature \ parse_signify_output refresh_signature recursive main "$@"