diff --git a/scripts/pkgmeek b/scripts/pkgmeek index d4b545e..85d02cf 100755 --- a/scripts/pkgmeek +++ b/scripts/pkgmeek @@ -10,18 +10,43 @@ main() { ######################## main routine ################################ local N pkg_dir src_dir work _local_ here url u pkg_utd f DIR TARGET local errDL=0; local errUZ=0; local BSDTAR="/usr/bin/bsdtar --format=gnutar" -declare -A ZFLAG=([xz]="-J" [bz2]="-j" [gz]="-z" [lz4]="--lz4" [zstd]="--zstd") +declare -A ZFLAG=([xz]="-J" [bz2]="-j" [gz]="-z" [lz]="--lzip" [lz4]="--lz4" [zst]="--zstd") +declare -A CMD_FLAGS parse_options "$@" # Exit early if refreshing an existing sha256 manifest was requested [ "$PKGMK_REFRESH_SIG" = "yes" ] && { make_signature refresh; exit $?; } -# + # Read the Pkgfile to determine what to do next. But first ensure that # it came from a trusted source (FS#1851) -# -[ "$PKGMK_UPDATE_SIG" = "yes" ] && [ -e ./Pkgfile ] || validate_pkgfile || exit $E_PKGFILE + +[ "${CMD_FLAGS[is]}${CMD_FLAGS[us]}" ] && PKGMK_IGNORE_SIG="yes" +validate_pkgfile || exit $E_PKGFILE [ -f .32bit ] && PKGMK_ARCH=32 || PKGMK_ARCH=64 . "Pkgfile"; . "$PKGMK_CONF" +if [ -z "$LIBC" ]; then + LIBC=$(pkginfo -o libc.so | awk '/libc.so/ {if ($1 == "glibc"){print "gnu"} else {print $1}}') +fi + +# Ensure that command-line flags take precedence +[ "${CMD_FLAGS[i]}" ] && PKGMK_INSTALL="yes" +[ "${CMD_FLAGS[u]}" ] && PKGMK_INSTALL="update" +[ "${CMD_FLAGS[d]}" ] && PKGMK_DOWNLOAD="yes" +[ "${CMD_FLAGS[do]}" ] && PKGMK_DOWNLOAD_ONLY="yes" +[ "${CMD_FLAGS[eo]}" ] && PKGMK_EXTRACT_ONLY="yes" +[ "${CMD_FLAGS[utd]}" ] && PKGMK_MTIME_ONLY="yes" +[ "${CMD_FLAGS[uf]}" ] && PKGMK_UPDATE_FOOTPRINT="yes" +[ "${CMD_FLAGS[if]}" ] && PKGMK_IGNORE_FOOTPRINT="yes" +[ "${CMD_FLAGS[in]}" ] && PKGMK_IGNORE_NEW="yes" +[ "${CMD_FLAGS[f]}" ] && PKGMK_FORCE="yes" +[ "${CMD_FLAGS[kw]}" ] && PKGMK_KEEP_WORK="yes" +[ "${CMD_FLAGS[us]}" ] && PKGMK_UPDATE_SIG="yes" +[ "${CMD_FLAGS[is]}" ] && PKGMK_IGNORE_SIG="yes" +[ "${CMD_FLAGS[cs]}" ] && PKGMK_CHECK_SIG="yes" +[ "${CMD_FLAGS[rs]}" ] && PKGMK_REFRESH_SIG="yes" +[ "${CMD_FLAGS[ns]}" ] && PKGMK_NO_STRIP="yes" +[ "${KEY_FILES[pk]}" ] && PKGMK_PUBLICKEY="${KEY_FILES[pk]}" +[ "${KEY_FILES[sk]}" ] && PKGMK_PRIVATEKEY="${KEY_FILES[sk]}" # respect the settings for centralized source and package directories ... [ -v pkg_dir ] || pkg_dir="$PKGMK_PACKAGE_DIR"/ @@ -37,17 +62,17 @@ parse_options "$@" package="${name}#${version}-${release}.pkg.tar.${PKGMK_COMPRESSION_MODE}" declare -a _local_ for (( s=0; s<${#source[@]}; s++ )); do - case "${source[s]}" in - http://*|https://*|ftp://*|__git__*) - _local_[s]="${source[s]##*/}" # strip the leading path - # and for git sources, extract the project name: - [[ "${source[s]}" =~ ^__git__ ]] && { _local_[s]="${_local_[s]%%\#*}"; - _local_[s]="${_local_[s]%.git}"; } ;; - *) - _local_[s]="${source[s]}" ;; - esac - [ -z "${renames[s]}" ] || [ "${renames[s]}" = "SKIP" ] || \ - _local_[s]="${renames[s]}" + case "${source[s]}" in + http://*|https://*|ftp://*|__git__*) + _local_[s]="${source[s]##*/}" # strip the leading path + # and for git sources, extract the project name: + [[ "${source[s]}" =~ ^__git__ ]] && { _local_[s]="${_local_[s]%%\#*}"; + _local_[s]="${_local_[s]%.git}"; } ;; + *) + _local_[s]="${source[s]}" ;; + esac + [ -z "${renames[s]}" ] || [ "${renames[s]}" = "SKIP" ] || \ + _local_[s]="${renames[s]}" done # Example: source = ( __git__https://gitlab.com/demo-user/cool-project.git#0.4.9 # https://dev.big-corp.com/src/needed-library.tgz @@ -62,8 +87,9 @@ done mkdir -p "$work"/{src,pkg} && cd "$work" # Skip the retrieval of sources if the user asked for '-utd' or '-uf'. -[[ "$PKGMK_MTIME_ONLY $PKGMK_UPDATE_FOOTPRINT" =~ yes ]] && [ -e "$PKGMK_PACKAGE_DIR/$package" ] \ - || { for (( u=0; u<${#_local_[@]}; u++ )); do +[[ "$PKGMK_MTIME_ONLY $PKGMK_UPDATE_FOOTPRINT" =~ yes ]] || \ + [ "$(type -t download_source)" = "function" ] || \ + { 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 @@ -73,14 +99,18 @@ here="${_local_[u]}"; url="${source[u]}"; [ -e "$here" ] || { error "failed to download $here. Check connection and try again."; errDL+=1; } done ; } -[ $errDL = 0 ] && { [[ "$PKGMK_MTIME_ONLY $PKGMK_UPDATE_FOOTPRINT" =~ yes ]] || \ - info "Successfully obtained all needed source files."; } || exit $E_DOWNLOAD +# accommodate the ports that redefine download_source() +if [[ ! "$PKGMK_MTIME_ONLY $PKGMK_UPDATE_FOOTPRINT" =~ yes ]] && [ "$(type -t download_source)" = "function" ] +then + download_source && info "Successfully obtained all needed source files." \ + || { error "failed to download sources."; exit $E_DOWNLOAD; } +fi # Can stop here if the user asked for '-do', but honor any requests for '-um', '-uf', # '-us', '-eo', or '-utd' by proceeding to those steps [ "$PKGMK_DOWNLOAD_ONLY" = "no" ] || [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ] \ - || [ "$PKGMK_UPDATE_SIG" = "yes" ] || [ "$PKGMK_EXTRACT_ONLY" = "yes" ] \ - || [ "$PKGMK_MTIME_ONLY" = "yes" ] || { cleanup_work; exit 0; } + || [ "$PKGMK_UPDATE_SIG" = "yes" ] || [ "$PKGMK_EXTRACT_ONLY" = "yes" ] \ + || [ "$PKGMK_MTIME_ONLY" = "yes" ] || { cleanup_work; exit 0; } # If '-utd' was requested, check the modification times and then exit. check_pkg_mtime; pkg_utd=$? @@ -89,25 +119,26 @@ check_pkg_mtime; pkg_utd=$? # Take into account all the actions that can be done without extracting # the downloaded sources [ "$pkg_utd" = 0 ] || [ "$PKGMK_FORCE" = "yes" ] || [ "$PKGMK_EXTRACT_ONLY" = "yes" ] \ - || [[ "$PKGMK_UPDATE_FOOTPRINT $PKGMK_CHECK_SIG $PKGMK_UPDATE_SIG" =~ yes ]] \ - || { info "$package is up to date, use '-f' to force a rebuild."; cleanup_work; exit 0; } + || [[ "$PKGMK_UPDATE_FOOTPRINT $PKGMK_CHECK_SIG $PKGMK_UPDATE_SIG" =~ yes ]] \ + || [ "$PKGMK_INSTALL" != "no" ] \ + || { info "$package is up to date, use '-f' to force a rebuild."; cleanup_work; exit 0; } # Silence the progress report if the user never intended to proceed with unpacking [ "$pkg_utd" = 1 ] || [[ "$PKGMK_CHECK_SIG $PKGMK_UPDATE_SIG" =~ yes ]] || \ - [[ "$PKGMK_IGNORE_SIG $PKGMK_UPDATE_FOOTPRINT" =~ yes ]] \ - || echo "Checking signatures before unpacking..." + [[ "$PKGMK_IGNORE_SIG $PKGMK_UPDATE_FOOTPRINT" =~ yes ]] \ + || echo "Checking signatures before unpacking..." # The option -uf is meant to be used *after* a previous invocation of pkgmeek has # alerted the user to a footprint mismatch. if [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ]; then - [ -f "$pkg_dir$package" ] || \ - { error "unable to update footprint. File '$package' not found."; - cleanup_work; exit "$E_FOOTPRINT"; } - [ "$pkg_utd" = 1 ] || [ "$PKGMK_FORCE" = "yes" ] || \ - { error "outdated package. Use '-f' to force the footprint update."; - cleanup_work; exit "$E_FOOTPRINT"; } - cat_footprint > "$PKGMK_ROOT/.footprint" && { info "footprint created."; exit 0; } \ - || { error "Failed to write the footprint."; cleanup_work; exit "$E_DIRPERM"; } + [ -f "$pkg_dir$package" ] || \ + { error "unable to update footprint. File '$package' not found."; + cleanup_work; exit "$E_FOOTPRINT"; } + [ "$pkg_utd" = 1 ] || [ "$PKGMK_FORCE" = "yes" ] || \ + { error "outdated package. Use '-f' to force the footprint update."; + cleanup_work; exit "$E_FOOTPRINT"; } + make_footprint > "$PKGMK_ROOT/.footprint" && { info "footprint created."; exit 0; } \ + || { error "Failed to write the footprint."; cleanup_work; exit "$E_DIRPERM"; } fi # Updating signatures (option -us) requires only sources and footprint, not a built package. # As with -uf, exit after fulfilling the explicit request for a manifest. @@ -117,81 +148,81 @@ fi 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" ; cleanup_work; exit $E_SIGNATURE ;; - 2) error "Failed to authenticate remote sources using signify." - echo "$cs_fail_msg" ; cleanup_work; exit $E_SIGNATURE ;; + 0) info "Sources successfully authenticated." ;; + 1) error "Signature file missing or corrupted." + echo "$cs_fail_msg" ; cleanup_work; exit $E_SIGNATURE ;; + 2) error "Failed to authenticate remote sources using signify." + echo "$cs_fail_msg" ; cleanup_work; exit $E_SIGNATURE ;; esac; } [ "$PKGMK_CHECK_SIG" = "no" ] || { cleanup_work; exit 0; } # no need to continue if the user only requested -cs if [ "$pkg_utd" = 0 ] || [[ "$PKGMK_FORCE $PKGMK_EXTRACT_ONLY" =~ yes ]]; then - if [ "$(type -t unpack_source)" = "function" ]; then - SRC=$PWD/src unpack_source || errUZ+=1 - else - for (( u=0; u<${#_local_[@]}; u++ )) ; do - here="${_local_[u]}" - case "$here" in - *.tar|*.tar.gz|*.tar.Z|*.tgz|*.tar.bz2|*.tbz2|*.tar.xz|*.txz|*.tar.lzma|*.tar.lz|*.7z|*.zip|*.rpm) - bsdtar -p -o -C src -xf "$here" || errUZ+=1 ;; - *) - cp -r -L "$here" src/ ;; - esac - done - fi - [ $errUZ = 0 ] && info "Sources successfully unpacked." || \ - { error "Failed to unpack all sources."; cleanup_work; exit "$E_UNPACK"; } - [ "$PKGMK_EXTRACT_ONLY" = "no" ] || exit 0 + if [ "$(type -t unpack_source)" = "function" ]; then + SRC=$PWD/src unpack_source || errUZ+=1 + else + for (( u=0; u<${#_local_[@]}; u++ )) ; do + here="${_local_[u]}" + case "$here" in + *.tar|*.tar.gz|*.tar.Z|*.tgz|*.tar.bz2|*.tbz2|*.tar.xz|*.txz|*.tar.lzma|*.tar.lz|*.7z|*.zip|*.rpm) + bsdtar -p -o -C src -xf "$here" || errUZ+=1 ;; + *) + cp -r -L "$here" src/ ;; + esac + done + fi + [ $errUZ = 0 ] && info "Sources successfully unpacked." || \ + { error "Failed to unpack all sources."; cleanup_work; exit "$E_UNPACK"; } + [ "$PKGMK_EXTRACT_ONLY" = "no" ] || exit 0 # The actual build step! (use fakeroot when building daemon ports as an ordinary user, # otherwise the owner and group might not be correct) - (SRC=$(pwd)/src; PKG=$(pwd)/pkg; cd src; set -e -x; build) - [ $? = 0 ] && echo "Build successful. Moving on to compression." \ - || { error "Unsuccessful build!"; cleanup_work; exit "$E_BUILD"; } + (SRC=$(pwd)/src; PKG=$(pwd)/pkg; cd src; set -e -x; build) + [ $? = 0 ] && echo "Build successful. Moving on to compression." \ + || { error "Unsuccessful build!"; cleanup_work; exit "$E_BUILD"; } - # Strip binaries - N=$(nproc) - [ -n "$ns_filter" ] || [ ! -f "$PKGMK_ROOT/.nostrip" ] \ - || ns_filter="| grep -v -f $PKGMK_ROOT/.nostrip" - ns_filter+="| xargs -r -L10 -P$N file --no-buffer --separator '>'" - ns_filter+=" -e apptype -e text -e encoding -e cdf -e compress -e tar" + # Strip binaries + N=$(nproc) + [ -n "$ns_filter" ] || [ ! -f "$PKGMK_ROOT/.nostrip" ] \ + || ns_filter="| grep -v -f $PKGMK_ROOT/.nostrip" + ns_filter+="| xargs -r -L10 -P$N file --no-buffer --separator '>'" + ns_filter+=" -e apptype -e text -e encoding -e cdf -e compress -e tar" - < <(eval find pkg -type f -printf "%P\n" $ns_filter) awk 'BEGIN { FS=">[ ]+" } - $0 ~ /ELF.*executable.*not stripped/ { print "--strip-all \"" $1 "\"" } - $0 ~ /ELF.*shared object.*not stripped/ { print "--strip-unneeded \"" $1 "\"" } - $2 == "current ar archive" { print "--strip-debug \"" $1 "\"" }' \ - | xargs -r -L1 -P$N strip + < <(eval find pkg -type f -printf "%P\n" $ns_filter) awk 'BEGIN { FS=">[ ]+" } + $0 ~ /ELF.*executable.*not stripped/ { print "--strip-all \"" $1 "\"" } + $0 ~ /ELF.*shared object.*not stripped/ { print "--strip-unneeded \"" $1 "\"" } + $2 == "current ar archive" { print "--strip-debug \"" $1 "\"" }' \ + | xargs -r -L1 -P$N strip - # Compress anything under /man that does not appear to be gzipped - find pkg -type f -path "*/man/man*/*" \! -iname '*.gz' \ - -exec gzip -9 '{}' + + # Compress anything under /man that does not appear to be gzipped + find pkg -type f -path "*/man/man*/*" \! -iname '*.gz' \ + -exec gzip -9 '{}' + - # Ensure that symlinks point to the (now-compressed) manpages - { while IFS="!" read -r f DIR; do - TARGET="$(readlink -n "$DIR/$f")" - TARGET="${TARGET##*/}"; TARGET="${TARGET%.gz}.gz"; - rm -f "$DIR/$f" - [ -e "$DIR/$TARGET" ] && ln -sf "$TARGET" "$DIR/${f%.gz}.gz" - done } < <(find pkg -type l -path "*/man/man*/*" -printf '%f!%h\n') + # Ensure that symlinks point to the (now-compressed) manpages + { while IFS="!" read -r f DIR; do + TARGET="$(readlink -n "$DIR/$f")" + TARGET="${TARGET##*/}"; TARGET="${TARGET%.gz}.gz"; + rm -f "$DIR/$f" + [ -e "$DIR/$TARGET" ] && ln -sf "$TARGET" "$DIR/${f%.gz}.gz" + done } < <(find pkg -type l -path "*/man/man*/*" -printf '%f!%h\n') - # Create the archive - BSDTAR+=" ${ZFLAG[$PKGMK_COMPRESSION_MODE]}" - [ $UID = 0 ] || BSDTAR+=" --uid 0 --gid 0" - [ -w "$pkg_dir$package" ] || rm -f "$pkg_dir$package" 2>/dev/null \ - || { error "$pkg_dir$package not writable."; - cleanup_work; exit "$E_BUILD"; } - if (cd pkg; $BSDTAR -cf "$pkg_dir$package" -- *); then - info "Package creation successful." - else - error "Unable to create the compressed package $package." - cleanup_work; exit "$E_BUILD" - fi + # Create the archive + BSDTAR+=" ${ZFLAG[$PKGMK_COMPRESSION_MODE]}" + [ $UID = 0 ] || BSDTAR+=" --uid 0 --gid 0" + [ -w "$pkg_dir$package" ] || rm -f "$pkg_dir$package" 2>/dev/null \ + || { error "$pkg_dir$package not writable."; + cleanup_work; exit "$E_BUILD"; } + if (cd pkg; $BSDTAR -cf "$pkg_dir$package" -- *); then + info "Package creation successful." + else + error "Unable to create the compressed package $package." + cleanup_work; exit "$E_BUILD" + fi - # Check the footprint of the built package, unless '-if' was given - [ "$PKGMK_IGNORE_FOOTPRINT" = "yes" ] || check_footprint + # Check the footprint of the built package, unless '-if' was given + [ "$PKGMK_IGNORE_FOOTPRINT" = "yes" ] || check_footprint - # Create signature if it doesn't already exist - [ -e "$PKGMK_ROOT/.signature" ] || make_signature new + # Create signature if it doesn't already exist + [ -e "$PKGMK_ROOT/.signature" ] || make_signature new fi # Continue from here if extract and build were skipped @@ -199,14 +230,14 @@ fi # Continue from here if extract and build were skipped find . -maxdepth 1 -mindepth 1 -type l -delete; cleanup_work # Proceed to install/upgrade if requested. -if [ -n "$PKGMK_INSTALL_COMMAND" ]; then - [ $UID = 0 ] && PKGMK_SU="" - [ -z "$PKGMK_SU" ] || [ -x "$PKGMK_SU" ] || PKGMK_SU="/usr/bin/doas" - [ -z "$PKGMK_SU" ] || [ -x "$PKGMK_SU" ] || - { error "Cannot run pkgadd as a non-root user."; exit "$E_INSTALL"; } - $PKGMK_SU $PKGMK_INSTALL_COMMAND "$pkg_dir$package" \ - && info "pkgadd $package succeeded." || \ - { error "pkgadd $package failed."; exit "$E_INSTALL"; } +if [ "$PKGMK_INSTALL" != "no" ]; then + PKGMK_INSTALL_COMMAND="/usr/bin/pkgadd" + [ "${CMD_FLAGS[pkgadd]}" ] && PKGMK_INSTALL_COMMAND="${CMD_FLAGS[pkgadd]}" + [ "${CMD_FLAGS[instroot]}" ] && PKGMK_INSTALL_COMMAND+=" -r ${CMD_FLAGS[instroot]}" + [ "$PKGMK_INSTALL" = "update" ] && PKGMK_INSTALL_COMMAND+=" -u" + $PKGMK_INSTALL_COMMAND "$pkg_dir$package" \ + && info "pkgadd $package succeeded." || \ + { error "pkgadd $package failed."; exit "$E_INSTALL"; } fi # Done! @@ -231,7 +262,7 @@ PKGMK_GIT_COMMAND="/usr/bin/git" PKGMK_CONF="/etc/pkgmk.conf"; PKGMK_SU="/usr/bin/sudo" PKGMK_SOURCE_DIR="$PWD"; PKGMK_WORK_DIR="$PWD/work" PKGMK_PACKAGE_DIR="$PWD"; PKGMK_COMPRESSION_MODE="gz" -PKGMK_INSTALL_COMMAND=""; PKGMK_FORCE="no" +PKGMK_INSTALL="no"; PKGMK_FORCE="no" PKGMK_DOWNLOAD_ONLY="no"; PKGMK_KEEP_WORK="no" PKGMK_EXTRACT_ONLY="no"; PKGMK_UPDATE_SIG="no" PKGMK_MTIME_ONLY="no"; PKGMK_IGNORE_SIG="no" @@ -241,344 +272,367 @@ PKGMK_IGNORE_NEW="no"; PKGMK_PRIVATEKEY="" ######################## subroutines ################################ parse_options() { - while [ "$1" ]; do - case "$1" in - -h|--help) print_help; exit 0 ;; - -v|--version) - echo "$(basename "$PKGMK_COMMAND") (pkgutils) $PKGMK_VERSION"; exit 0 ;; - -uf|--update-footprint) PKGMK_UPDATE_FOOTPRINT="yes" ;; - -us|--update-signature) PKGMK_UPDATE_SIG="yes" ;; - -rs|--refresh-signature) PKGMK_REFRESH_SIG="yes" ;; - -cs|--check-signature) PKGMK_CHECK_SIG="yes" ;; - -d|--download) ;; # deprecated flags but don't throw an error for them - -um|--update-md5sum) warn "updating md5sums is obsolete, ignoring option '$1'." ;; - -r|--recursive) { warn "option '$1' no longer supported. Use a wrapper script for recursive operation."; exit 1; } ;; - -c|--clean) { error "option '$1' no longer implemented in $(basename "$PKGMK_COMMAND"). Use prtwash instead."; exit 1; } ;; - -do|--download-only) PKGMK_DOWNLOAD_ONLY="yes" ;; - -eo|--extract-only) PKGMK_EXTRACT_ONLY="yes" ;; - -utd|--up-to-date) PKGMK_MTIME_ONLY="yes" ;; - -if|--ignore-footprint) PKGMK_IGNORE_FOOTPRINT="yes" ;; - -in|--ignore-new) PKGMK_IGNORE_NEW="yes" ;; - -is|--ignore-signature) PKGMK_IGNORE_SIG="yes" ;; - -ns|--no-strip) ns_filter="-false" ;; - -f|--force) PKGMK_FORCE="yes" ;; - -kw|--keep-work) PKGMK_KEEP_WORK="yes" ;; - -i|--install) PKGMK_INSTALL_COMMAND="/usr/bin/pkgadd" ;; - -u|--upgrade) PKGMK_INSTALL_COMMAND="/usr/bin/pkgadd -u" ;; - -pk|--public-key) - [ "$2" ] && PKGMK_PUBLICKEY="$2" || { echo "$(basename "$PKGMK_COMMAND"): option $1 requires an argument"; - exit 1; } - shift ;; - -sk|--secret-key) - [ "$2" ] && PKGMK_PRIVATEKEY="$2" || { echo "$(basename "$PKGMK_COMMAND"): option $1 requires an argument"; - exit 1; } - shift ;; - -cf|--config-file) - [ "$2" ] && PKGMK_CONF="$2" || { echo "$(basename "$PKGMK_COMMAND"): option $1 requires an argument"; - exit 1; } - shift ;; - *) - echo "$(basename "$PKGMK_COMMAND"): invalid option $1"; exit 1 ;; - esac - shift - done + local needHelp && declare -a needHelp + while [ "$1" ]; do + case "$1" in + -h|--help) needHelp+=("help") ;; + -v|--version) needHelp+=("version") ;; + -uf|-us|-rs|-cs|-um|-do|-eo|-if|-is|-in|-ns|-f|-kw|-i|-u) CMD_FLAGS["${1#-}"]=1 ;; + --update-signature) CMD_FLAGS["us"]=1 ;; + --refresh-signature) CMD_FLAGS["rs"]=1 ;; + --check-signature) CMD_FLAGS["cs"]=1 ;; + -d|--download) ;; # deprecated flags but don't throw an error for them + -utd|--up-to-date) CMD_FLAGS["utd"]=1 ;; + --download-only) CMD_FLAGS["do"]=1 ;; + --extract-only) CMD_FLAGS["eo"]=1 ;; + --ignore-footprint) CMD_FLAGS["if"]=1 ;; + --ignore-new) CMD_FLAGS["in"]=1 ;; + --ignore-signature) CMD_FLAGS["is"]=1 ;; + --no-strip) ns_filter="-false" ;; + --force) CMD_FLAGS["f"]=1 ;; + --keep-work) CMD_FLAGS["kw"]=1 ;; + --install) CMD_FLAGS["i"]=1 ;; + --upgrade) CMD_FLAGS["u"]=1 ;; + -pk|--public-key) + [ -r "$2" ] && KEY_FILES["pk"]="$2" || { echo "$(basename "$PKGMK_COMMAND"): option $1 requires a filename as argument"; + exit 1; } + shift ;; + -sk|--secret-key) + [ -r "$2" ] && KEY_FILES["sk"]="$2" || { echo "$(basename "$PKGMK_COMMAND"): option $1 requires a filename as argument"; + exit 1; } + shift ;; + -cf|--config-file) + [ -r "$2" ] && PKGMK_CONF="$2" || { echo "$(basename "$PKGMK_COMMAND"): option $1 requires a filename as argument"; + exit 1; } + shift ;; + --install-root) + [ -d "$2" ] && CMD_FLAGS["rootfs"]="$2" || { echo "$(basename "$PKGMK_COMMAND"): option $1 requires a mountpoint as argument"; + exit 1; } + shift ;; + --addcommand) + [ "$2" ] && CMD_FLAGS["pkgadd"]="$2" || { echo "$(basename "$PKGMK_COMMAND"): option $1 requires a path to pkgadd"; + exit 1; } + shift ;; + -um|--update-md5sum) warn "updating md5sums is obsolete, ignoring option '$1'." ;; + -r|--recursive) { warn "option '$1' no longer supported. Use a wrapper script for recursive operation."; exit 1; } ;; + -c|--clean) { error "option '$1' no longer implemented in $(basename "$PKGMK_COMMAND"). Use prtwash instead."; exit 1; } ;; + *) + echo "$(basename "$PKGMK_COMMAND"): invalid option $1"; exit 1 ;; + esac + shift + done + if [ ${#needHelp[@]} != 0 ]; then + for ((i=0; i<${#needHelp[@]}; i++)); do + case "${needHelp[i]}" in + help) print_help ;; + version) echo "$(basename "$PKGMK_COMMAND") (pkgutils) $PKGMK_VERSION" ;; + esac + done + exit 0 + fi } print_help() { - echo "usage: $(basename "$PKGMK_COMMAND") [options]" - echo "options: (highest to lowest precedence)" - echo " -h, --help print help and exit" - echo " -v, --version print version and exit" - echo " -cf, --config-file use alternative configuration file" - echo " -sk, --secret-key use to sign the port" - echo " -pk, --public-key check the port signature using public-key " - echo " -rs, --refresh-signature create new signature based on existing sha256 checksums" - echo " -utd, --up-to-date report whether the built package is up to date, then exit" - echo " -f, --force override timestamp check, build package or update footprint anyway" - echo " -uf, --update-footprint update footprint using result from last build" - echo " -do, --download-only stop after downloading all the necessary source file(s)" - echo " -cs, --check-signature stop after verifying the signatures of all downloaded sources" - echo " -us, --update-signature update signature of Pkgfile and sources, do not build" - echo " -is, --ignore-signature build package without checking signature" - echo " -eo, --extract-only stop after downloading and extracting source file(s)" - echo " -ns, --no-strip do not strip executable binaries or libraries" - echo " -kw, --keep-work keep temporary working directory" - echo " -if, --ignore-footprint build package without checking footprint" - echo " -in, --ignore-new build package, ignoring new files in a footprint mismatch" - echo " -i, --install build and install package" - echo " -u, --upgrade build and upgrade package" + echo "usage: $(basename "$PKGMK_COMMAND") [options]" + echo "options: (highest to lowest precedence)" + echo " -h, --help print help and exit" + echo " -v, --version print version and exit" + echo " -cf, --config-file use alternative configuration file" + echo " -sk, --secret-key use to sign the port" + echo " -pk, --public-key check the port signature using public-key " + echo " -rs, --refresh-signature create new signature based on existing sha256 checksums" + echo " -utd, --up-to-date report whether the built package is up to date, then exit" + echo " -f, --force override timestamp check, build package or update footprint anyway" + echo " -uf, --update-footprint update footprint using result from last build" + echo " -do, --download-only stop after downloading all the necessary source file(s)" + echo " -cs, --check-signature stop after verifying the signatures of all downloaded sources" + echo " -us, --update-signature update signature of Pkgfile and sources, do not build" + echo " -is, --ignore-signature build package without checking signature" + echo " -eo, --extract-only stop after downloading and extracting source file(s)" + echo " -ns, --no-strip do not strip executable binaries or libraries" + echo " -kw, --keep-work keep temporary working directory" + echo " -if, --ignore-footprint build package without checking footprint" + echo " -in, --ignore-new build package, ignoring new files in a footprint mismatch" + echo " -i, --install build and install package" + echo " -u, --upgrade build and upgrade package" + echo " --install-root install package to the CRUX system mounted at " + echo " --addcommand specify an alternative pkgadd command" } validate_pkgfile() { # called from within PKGMK_ROOT - local errcode kv - [ -f Pkgfile ] || { error "no Pkgfile found. $PKGMK_ROOT is not a valid ports directory."; return "$E_PKGFILE"; } - check_signature "pre-Pkgfile" | parse_signify_output - errcode=$? - [ "$errcode" = 0 ] || info "Use '-is' if you have independent confirmation of the port's integrity." - [ "$errcode" = 0 ] || [ "$PKGMK_IGNORE_SIG" = "yes" ] || return $E_SIGNATURE + local errcode kv + [ -f Pkgfile ] || { error "no Pkgfile found. $PKGMK_ROOT is not a valid ports directory."; return "$E_PKGFILE"; } + [ "$PKGMK_UPDATE_SIG" = "yes" ] && return 0 + check_signature "pre-Pkgfile" | parse_signify_output + errcode=$? + [ "$errcode" = 0 ] || info "Use '-is' if you have independent confirmation of the port's integrity." + [ "$errcode" = 0 ] || [ "$PKGMK_IGNORE_SIG" = "yes" ] || return $E_SIGNATURE - # the environment should not be affected by sourcing the Pkgfile both here - # and in the later build, but to be safe we use a nested subshell - ( . Pkgfile; kv=0; [ -n "$name" ] || kv+=1; [ -n "$version" ] || kv+=2; \ - [ -n "$release" ] || kv+=4; [ "$(type -t build)" = "function" ] || kv+=8; \ - echo $kv ) | check_reqvars + # the environment should not be affected by sourcing the Pkgfile both here + # and in the later build, but to be safe we use a nested subshell + ( . Pkgfile; kv=0; [ -n "$name" ] || kv+=1; [ -n "$version" ] || kv+=2; \ + [ -n "$release" ] || kv+=4; [ "$(type -t build)" = "function" ] || kv+=8; \ + echo $kv ) | check_reqvars } check_reqvars () { - local checksum nullvars; - read -r checksum - [ $((checksum & 1)) = 1 ] && nullvars=" 'name'" - [ $((checksum & 2)) = 2 ] && nullvars+=" 'version'" - [ $((checksum & 4)) = 4 ] && nullvars+=" 'release'" - [ $((checksum & 8)) = 8 ] && nullvars+=" 'build()'" - [ "$checksum" = 0 ] || { error "Pkgfile does not specify these required variables:"; \ - info "$nullvars"; return "$E_PKGFILE"; } + local checksum nullvars; + read -r checksum + [ $((checksum & 1)) = 1 ] && nullvars=" 'name'" + [ $((checksum & 2)) = 2 ] && nullvars+=" 'version'" + [ $((checksum & 4)) = 4 ] && nullvars+=" 'release'" + [ $((checksum & 8)) = 8 ] && nullvars+=" 'build()'" + [ "$checksum" = 0 ] || { error "Pkgfile does not specify these required variables:"; \ + info "$nullvars"; return "$E_PKGFILE"; } } check_pkg_mtime() { # can be called even if some sources are missing - local li=0; local utd=0; local msg="$package is not up to date." + local li=0; local utd=0; local msg="$package is not up to date." - if [ -f "$pkg_dir$package" ]; then - utd=1 - while (( li < ${#_local_[@]} )) && [ "$utd" = 1 ]; do - [ ! -e "${_local_[li]}" ] || \ - [ "$pkg_dir$package" -nt "$(realpath "${_local_[$li]}")" ] || utd=0 - li=$(( li+1 )) - done - [ ! -e "$PKGMK_ROOT/Pkgfile" ] || [ "$pkg_dir$package" -nt "$PKGMK_ROOT/Pkgfile" ] || utd=0 - fi + if [ -f "$pkg_dir$package" ]; then + utd=1 + while (( li < ${#_local_[@]} )) && [ "$utd" = 1 ]; do + [ ! -e "${_local_[li]}" ] || \ + [ "$pkg_dir$package" -nt "$(realpath "${_local_[$li]}")" ] || utd=0 + li=$(( li+1 )) + done + [ ! -e "$PKGMK_ROOT/Pkgfile" ] || [ "$pkg_dir$package" -nt "$PKGMK_ROOT/Pkgfile" ] || utd=0 + else + msg="$package is not yet built." + utd=0 + fi - [ $utd = 0 ] || msg="$package is up to date." - [ "$PKGMK_MTIME_ONLY" = "yes" ] && info "$msg"; return $utd + [ $utd = 0 ] || msg="$package is up to date." + [ "$PKGMK_MTIME_ONLY" = "yes" ] && info "$msg"; return $utd } get_basename() { - echo "${1##*/}" + echo "${1##*/}" } get_filename() { - local ABSOLUTE="" - [ "$1" = "-a" ] && { ABSOLUTE=1; shift; } + local ABSOLUTE="" + [ "$1" = "-a" ] && { ABSOLUTE=1; shift; } - if [[ $1 =~ ^(http|https|ftp|file)://.*/(.+) ]]; then - echo "$PKGMK_SOURCE_DIR/${BASH_REMATCH[2]}" - else - [ "$ABSOLUTE" ] && echo "$PKGMK_ROOT/$1" || echo "$1" - fi + if [[ $1 =~ ^(http|https|ftp|file)://.*/(.+) ]]; then + echo "$PKGMK_SOURCE_DIR/${BASH_REMATCH[2]}" + else + [ "$ABSOLUTE" ] && echo "$PKGMK_ROOT/$1" || echo "$1" + fi } fetch_url() { - local u="$1"; local h="$2"; local finished=0; local giturl tag CLONE_ARGS - local SAVE_AS REPO OCONTINUE OOUT; local m=0 + local u="$1"; local h="$2"; local finished=0; local giturl tag CLONE_ARGS + local SAVE_AS REPO OCONTINUE OOUT; local m=0 - if [[ "$u" =~ ^__git__ ]]; then - # git must be installed in order to obtain such a source - [ -x "$PKGMK_GIT_COMMAND" ] || return 1; - # - giturl="${u#__git__}" - # Did the port maintainer specify a branch other than 'main'? - tag="${giturl##*\#}" - [ "$tag" = "$giturl" ] || { giturl="${giturl%\#*}"; - CLONE_ARGS=(-c advice.detachedHead=false --branch "$tag"); } - # - # Has this project been downloaded before? - if [ -d "$src_dir/$h.partial" ]; then - ln -s "$src_dir/$h.partial" "$h"; cd "$h" - "$PKGMK_GIT_COMMAND" pull "$giturl" "$tag" - finished=$?; cd .. - else - "$PKGMK_GIT_COMMAND" clone "$giturl" "${CLONE_ARGS[@]}" "$h.partial" - finished=$?; [ "$src_dir" = "" ] || { mv "$h.partial" "$src_dir"; - ln -s "$src_dir/$h.partial" "$h"; } - fi - return $finished; - else - case "$PKGMK_DOWNLOAD_PROG" in - *wget) OCONTINUE="-c" - OOUT="--compression=none --passive-ftp - --no-directories --tries=3 --waitretry=3 - $PKGMK_WGET_OPTIONS -O" ;; - *curl) OCONTINUE="-C -" - OOUT="-L -# --fail --ftp-pasv - --retry 3 --retry-delay 3 - $PKGMK_CURL_OPTIONS -o" ;; - *) SAVE_AS="false" ;; - esac - # - # start with the mirrors defined in pkgmk.conf, then go to the url found in the Pkgfile - while (( m <= ${#PKGMK_SOURCE_MIRRORS[@]} )) && [ $finished = 0 ] \ - && [ "$SAVE_AS" != "false" ]; do - [ "${PKGMK_SOURCE_MIRRORS[m]}" = "" ] && um=$u || \ - { REPO=${PKGMK_SOURCE_MIRRORS[m]%/}; um=$REPO/${u##*/}; } - m=$(( m+1 )) - # interrupted downloads from a previous run should be put where wget or curl will find them - [ -f "$src_dir/$h.partial" ] && { ln -s "$src_dir/$h.partial" . ; - SAVE_AS="$PKGMK_DOWNLOAD_PROG $um $OCONTINUE $OOUT"; } \ - || SAVE_AS="$PKGMK_DOWNLOAD_PROG $um $OOUT" - if $SAVE_AS "$h.partial"; then - finished=1 - [ "$src_dir" = "" ] || [ ! -w "$src_dir"/ ] || \ - { mv "$h.partial" "$src_dir/$h"; ln -sf "$src_dir/$h" . ; } - else # an interrupted download should not have its efforts destroyed by cleanup_work() - [ ! -s "$h.partial" ] || [ "$src_dir" = "" ] || \ - [ ! -w "$src_dir"/ ] || mv "$h.partial" "$src_dir" - fi - done - fi + if [[ "$u" =~ ^__git__ ]]; then + # git must be installed in order to obtain such a source + [ -x "$PKGMK_GIT_COMMAND" ] || return 1; + # + giturl="${u#__git__}" + # Did the port maintainer specify a branch other than 'main'? + tag="${giturl##*\#}" + [ "$tag" = "$giturl" ] || { giturl="${giturl%\#*}"; + CLONE_ARGS=(-c advice.detachedHead=false --branch "$tag"); } + # + # Has this project been downloaded before? + if [ -d "$src_dir/$h.partial" ]; then + ln -s "$src_dir/$h.partial" "$h"; cd "$h" + "$PKGMK_GIT_COMMAND" pull "$giturl" "$tag" + finished=$?; cd .. + else + "$PKGMK_GIT_COMMAND" clone "$giturl" "${CLONE_ARGS[@]}" "$h.partial" + finished=$?; [ "$src_dir" = "" ] || { mv "$h.partial" "$src_dir"; + ln -s "$src_dir/$h.partial" "$h"; } + fi + return $finished; + else + case "$PKGMK_DOWNLOAD_PROG" in + *wget) OCONTINUE="-c" + OOUT="--compression=none --passive-ftp + --no-directories --tries=3 --waitretry=3 + $PKGMK_WGET_OPTIONS -O" ;; + *curl) OCONTINUE="-C -" + OOUT="-L -# --fail --ftp-pasv + $PKGMK_CURL_OPTIONS -o" ;; + *) SAVE_AS="false" ;; + esac + # + # start with the mirrors defined in pkgmk.conf, then go to the url found in the Pkgfile + while (( m <= ${#PKGMK_SOURCE_MIRRORS[@]} )) && [ $finished = 0 ] \ + && [ "$SAVE_AS" != "false" ]; do + [ "${PKGMK_SOURCE_MIRRORS[m]}" = "" ] && um=$u || \ + { REPO=${PKGMK_SOURCE_MIRRORS[m]%/}; um=$REPO/${u##*/}; } + m=$(( m+1 )) + # interrupted downloads from a previous run should be put where wget or curl will find them + [ -f "$src_dir/$h.partial" ] && { ln -s "$src_dir/$h.partial" . ; + SAVE_AS="$PKGMK_DOWNLOAD_PROG $um $OCONTINUE $OOUT"; } \ + || SAVE_AS="$PKGMK_DOWNLOAD_PROG $um $OOUT" + if $SAVE_AS "$h.partial"; then + finished=1 + [ "$src_dir" = "" ] || [ ! -w "$src_dir"/ ] || \ + { mv "$h.partial" "$src_dir/$h"; ln -sf "$src_dir/$h" . ; } + else # an interrupted download should not have its efforts destroyed by cleanup_work() + [ ! -s "$h.partial" ] || [ "$src_dir" = "" ] || \ + [ ! -w "$src_dir"/ ] || mv "$h.partial" "$src_dir" + fi + done + fi } -cat_footprint() { - pkginfo --footprint "$pkg_dir$package" \ - | sed "s|\tlib/modules/$(uname -r)/|\tlib/modules//|g" \ - | sort -k 3 +make_footprint() { + pkginfo --footprint "$pkg_dir$package" \ + | sed -e "s|\tlib/modules/$(uname -r)/|\tlib/modules//|g" \ + | sort -k 3 } check_footprint() { - local CN CM - local TRUTH="$PKGMK_ROOT/.footprint"; local diffs=0; local severity=error; - [ -f "$pkg_dir$package" ] || \ - { error "$package not found. Cannot check footprint."; exit "$E_FOOTPRINT"; } + local CN CM + local TRUTH="$PKGMK_ROOT/.footprint"; local diffs=0; local severity=error; + [ -f "$pkg_dir$package" ] || \ + { error "$package not found. Cannot check footprint."; exit "$E_FOOTPRINT"; } - if [ -f "$TRUTH" ]; then - diff -w -t -U 0 <(sort "$TRUTH") <(cat_footprint | sort) | \ - sed '/^@@/d; /^+++/d; /^---/d; s/^+/NEW /g; s/^-/MISSING /g' > ".footprint.diff" - if [ -s ".footprint.diff" ]; then - CN=$(grep -c ^NEW ".footprint.diff"); CM=$(grep -c ^MISSING ".footprint.diff") - [ "$PKGMK_IGNORE_MISSING" = "yes" ] || diffs=$CM - [ "$PKGMK_IGNORE_NEW" = "yes" ] || diffs=$(( diffs+CN )) - (( diffs == 0 )) && severity=warning - $severity "footprint mismatch found:"; cat ".footprint.diff" >&2 - fi - rm ".footprint.diff" - else - warning "footprint not found, creating new."; cat_footprint > "$TRUTH" - fi - (( diffs == 0 )) || { cleanup_work; exit $E_FOOTPRINT; } + if [ -f "$TRUTH" ]; then + diff -w -t -U 0 <(sed "s;x86_64-linux-\(gnu\|musl\);x86_64-linux-LIBC;" "$TRUTH" | sort) \ + <(make_footprint | sed "s;x86_64-linux-\(gnu\|musl\);x86_64-linux-LIBC;" | sort) | \ + sed '/^@@/d; /^+++/d; /^---/d; s/^+/NEW /g; s/^-/MISSING /g' > ".footprint.diff" + if [ -s ".footprint.diff" ]; then + CN=$(grep -c ^NEW ".footprint.diff"); CM=$(grep -c ^MISSING ".footprint.diff") + [ "$PKGMK_IGNORE_NEW" = "yes" ] || diffs=$CN + [ "$PKGMK_IGNORE_FOOTPRINT" = "yes" ] && diffs=0 || diffs=$(( diffs+CM )) + (( diffs == 0 )) && severity=warning + $severity "footprint mismatch found:"; cat ".footprint.diff" >&2 + fi + rm ".footprint.diff" + else + warning "footprint not found, creating new."; make_footprint > "$TRUTH" + fi + (( diffs == 0 )) || { cleanup_work; exit $E_FOOTPRINT; } } parse_signify_output() { # chomps the output of check_signature() - local signout signerr - [ "$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; error "Signature file corrupted or unreadable." - ;; - *"FAIL") - signerr=2; error "Signature mismatch found:" - echo "$signout" | awk -F: '/FAIL/ {printf "MISMATCH %s\n", $1}' - ;; - *"OK") signerr=0 ;; - esac - done - return $signerr + local signout signerr + [ "$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; error "Signature file corrupted or unreadable." + ;; + *"FAIL") + signerr=2; error "Signature mismatch found:" + echo "$signout" | awk -F: '/FAIL/ {printf "MISMATCH %s\n", $1}' + ;; + *"OK") signerr=0 ;; + esac + done + return $signerr } check_signature() { # called from $PKGMK_ROOT in the case "when"="pre-Pkgfile", # otherwise called from within $work. - local reqfiles=(Pkgfile); local s=0; local when="$1"; - local SIGNIFY_ARGS=(-C -x "$PKGMK_ROOT/.signature") + local reqfiles=(Pkgfile); local s=0; local when="$1"; + local SIGNIFY_ARGS=(-C -x "$PKGMK_ROOT/.signature") - [ "$PKGMK_PUBLICKEY" ] || PKGMK_PUBLICKEY="$(get_repo_key public)" - if [ -f "$PKGMK_ROOT/.signature" ]; then - [ "$when" = "pre-Pkgfile" ] || reqfiles=(.footprint) - while [ "$when" = "pre-build" ] && (( s < ${#_local_[@]} )); do - [[ "${source[s]}" =~ ^__git__ ]] || reqfiles+=("${_local_[s]}") - s=$(( s+1 )) - done - for FILE in "${reqfiles[@]}"; do - [ -e "$FILE" ] || ln -sf "$PKGMK_ROOT/$FILE" . - done - [ -r "$PKGMK_PUBLICKEY" ] && SIGNIFY_ARGS+=(-p "$PKGMK_PUBLICKEY") - /usr/bin/signify "${SIGNIFY_ARGS[@]}" "${reqfiles[@]}" 2>&1 - else - [ "$when" = "pre-Pkgfile" ] && echo "Pkgfile verification failed" - [ "$when" != "pre-Pkgfile" ] && echo "signature verification failed" - fi + [ "$PKGMK_PUBLICKEY" ] || PKGMK_PUBLICKEY="$(get_repo_key public)" + if [ -f "$PKGMK_ROOT/.signature" ]; then + [ "$when" = "pre-Pkgfile" ] || reqfiles=(.footprint) + while [ "$when" = "pre-build" ] && (( s < ${#_local_[@]} )); do + [[ "${source[s]}" =~ ^__git__ ]] || reqfiles+=("${_local_[s]}") + s=$(( s+1 )) + done + for FILE in "${reqfiles[@]}"; do + [ -e "$FILE" ] || ln -sf "$PKGMK_ROOT/$FILE" . + done + [ -r "$PKGMK_PUBLICKEY" ] && SIGNIFY_ARGS+=(-p "$PKGMK_PUBLICKEY") + /usr/bin/signify "${SIGNIFY_ARGS[@]}" "${reqfiles[@]}" 2>&1 + else + [ "$when" = "pre-Pkgfile" ] && echo "Pkgfile verification failed" + [ "$when" != "pre-Pkgfile" ] && echo "signature verification failed" + fi } get_repo_key() { - local typ="${1:0:3}"; local REPO; - REPO=$(dirname "$PKGMK_ROOT"); REPO=$(basename -s .git "$REPO"); - ls "/etc/ports/$REPO.$typ" 2>/dev/null \ - || ls "$HOME/.ssh/$REPO.$typ" 2>/dev/null + local typ="${1:0:3}"; local REPO; + REPO=$(dirname "$PKGMK_ROOT"); REPO=$(basename -s .git "$REPO"); + ls "/etc/ports/$REPO.$typ" 2>/dev/null \ + || ls "$HOME/.ssh/$REPO.$typ" 2>/dev/null } make_signature() { - local ordered si pub - [ ! -e "$PKGMK_ROOT/.signature" ] || [ -w "$PKGMK_ROOT/.signature" ] \ - || { error ".signature not writable."; return $E_DIRPERM; } + local ordered si pub + [ ! -e "$PKGMK_ROOT/.signature" ] || [ -w "$PKGMK_ROOT/.signature" ] \ + || { error ".signature not writable."; return $E_DIRPERM; } - [ -n "$PKGMK_PRIVATEKEY" ] || PKGMK_PRIVATEKEY="$(get_repo_key secret)" - if [ -n "$PKGMK_PRIVATEKEY" ]; then - pub="/etc/ports/$(basename -s .sec "$PKGMK_PRIVATEKEY").pub" - elif [[ "$PKGMK_UPDATE_SIG$PKGMK_REFRESH_SIG" =~ yes ]]; then - error "No suitable secret key found. Specify one explicitly with '-sk'." - return $E_SIGNATURE - else - return 0 - fi + [ -n "$PKGMK_PRIVATEKEY" ] || PKGMK_PRIVATEKEY="$(get_repo_key secret)" + if [ -n "$PKGMK_PRIVATEKEY" ]; then + pub="/etc/ports/$(basename -s .sec "$PKGMK_PRIVATEKEY").pub" + elif [[ "$PKGMK_UPDATE_SIG$PKGMK_REFRESH_SIG" =~ yes ]]; then + error "No suitable secret key found. Specify one explicitly with '-sk'." + return $E_SIGNATURE + else + return 0 + fi - # create a new .signature, or refresh an existing manifest? - case "$1" in - new) - [ -e "$PKGMK_ROOT/.footprint" ] || \ - warning "Footprint not found, signature will be incomplete." - for f in "$PKGMK_ROOT/Pkgfile" "$PKGMK_ROOT/.footprint"; do - [ -e "$f" ] && ordered+=( "$f" ) - done - for ((si=0; si < ${#source[@]}; si++)); do - # ignore git directories when writing the signature - [[ "${source[si]}" =~ ^__git__ ]] || ordered+=("${_local_[si]}") - done - sha256sum --tag "${ordered[@]}" \ - | sed 's|^SHA256 (.*/\(.*\))\(.* = .*\)|SHA256 (\1)\2|' \ - | /usr/bin/signify -S -e -x - -q -s "$PKGMK_PRIVATEKEY" -m - \ - | sed "s|${PKGMK_PRIVATEKEY%.sec}.pub|$pub|" \ - > "$PKGMK_ROOT/.signature" - ;; - refresh) - [ -e ".signature" ] || \ - { error "missing .signature, cannot refresh."; return $E_SIGNATURE; } - if tail -n +3 ".signature" | /usr/bin/signify -S -e -x - -q \ - -s "$PKGMK_PRIVATEKEY" -m - > .signature.tmp; then - mv .signature.tmp .signature - else - rm .signature.tmp; return $E_SIGNATURE - fi - ;; - esac - [ "$1" = "new" ] && info "signature created." || info "signature updated." + # create a new .signature, or refresh an existing manifest? + case "$1" in + new) + [ -e "$PKGMK_ROOT/.footprint" ] || \ + warning "Footprint not found, signature will be incomplete." + for f in "$PKGMK_ROOT/Pkgfile" "$PKGMK_ROOT/.footprint"; do + [ -e "$f" ] && ordered+=( "$f" ) + done + for ((si=0; si < ${#source[@]}; si++)); do + # ignore git directories when writing the signature + [[ "${source[si]}" =~ ^__git__ ]] || ordered+=("${_local_[si]}") + done + sha256sum --tag "${ordered[@]}" \ + | sed 's|^SHA256 (.*/\(.*\))\(.* = .*\)|SHA256 (\1)\2|' \ + | /usr/bin/signify -S -e -x - -q -s "$PKGMK_PRIVATEKEY" -m - \ + | sed "s|${PKGMK_PRIVATEKEY%.sec}.pub|$pub|" \ + > "$PKGMK_ROOT/.signature" + ;; + refresh) + [ -e ".signature" ] || \ + { error "missing .signature, cannot refresh."; return $E_SIGNATURE; } + if tail -n +3 ".signature" | /usr/bin/signify -S -e -x - -q \ + -s "$PKGMK_PRIVATEKEY" -m - > .signature.tmp; then + mv .signature.tmp .signature + else + rm .signature.tmp; return $E_SIGNATURE + fi + ;; + esac + [ "$1" = "new" ] && info "signature created." || info "signature updated." } interrupted() { - error "Interrupted."; cleanup_work; exit 1 + error "Interrupted."; cleanup_work; exit 1 } cleanup_work() { - [ "$PKGMK_KEEP_WORK" = "yes" ] || { cd "$PKGMK_ROOT"; rm -rf "$work"; } + [ "$PKGMK_KEEP_WORK" = "yes" ] || { cd "$PKGMK_ROOT"; rm -rf "$work"; } } info() { - echo "=======> $1" + echo "=======> $1" } warning() { - info "WARNING: $1" >&2 + info "WARNING: $1" >&2 } error() { - info "ERROR: $1" >&2 + info "ERROR: $1" >&2 } ######################## end of subroutines ########################### -## Now ensure that they cannot be overwritten when sourcing Pkgfile ## +## Now ensure that some of them cannot be overwritten when sourcing Pkgfile ## readonly -f main info warning error print_help parse_options validate_pkgfile \ - check_reqvars check_pkg_mtime fetch_url cat_footprint check_footprint \ - make_signature get_repo_key check_signature parse_signify_output cleanup_work + check_reqvars check_pkg_mtime fetch_url get_repo_key \ + check_signature parse_signify_output cleanup_work trap "interrupted" SIGHUP SIGINT SIGQUIT SIGTERM export LC_ALL=C.UTF-8 diff --git a/scripts/prt-auf b/scripts/prt-auf index 0514a93..0c56e0d 100755 --- a/scripts/prt-auf +++ b/scripts/prt-auf @@ -21,7 +21,7 @@ my %osearch = ( cache=>0, regex=>0, path=>0, exact=>0, verbose=>0 ); my %odepends = ( inject=>1, soft=>0, tree=>0, recursive=>0, all=>0 ); my %opkg = ( margs=>"", aargs=>"", rargs=>"", run_scripts=>"no", pre_install=>"no", post_install=>"no", scriptcommand=>"/bin/sh", - removecommand=>"/usr/bin/pkgrm", addcommand=>"/usr/bin/pkgadd", + removecommand=>"/usr/bin/pkgrm", addcommand=>"", makecommand=>"/usr/bin/pkgmk", nolock=>0, test=>"no", group=>"no" ); my %olog = ( write => "disabled", mode => "overwrite", rm_on_success => "yes", rm_on_uninst => "no", file => "/var/log/pkgbuild/%n.log" ); @@ -128,7 +128,7 @@ if (($action =~ /^(listinst|listorphans|dependent)/) print "\n" if ($action eq "quickdiff"); exit $ind; } elsif ($action =~ /^(depends|quickdep)$/) { - print "-- dependency list ([i] = installed)\n" if ($action =~ /^dep/); + print "-- dependency list ([i] = installed, [u] = updateable)\n" if ($action =~ /^dep/); my $strf="%3s %s\n"; my $dep; my $missing=0; foreach $dep (@results) { if ($dep =~ /MISSING/) { @@ -137,6 +137,7 @@ if (($action =~ /^(listinst|listorphans|dependent)/) next if (! $dep); if ($action ne "quickdep") { $ind = (grep { $_ eq $dep } keys %V_INST) ? "[i]" : "[ ]"; + ($ind eq "[ ]") or (! $V_REPO{$dep}) or ($V_REPO{$dep} eq $V_INST{$dep}) or $ind = "[u]"; $dep .= " $V_REPO{$dep}" if (($osearch{verbose}==1) and ($V_REPO{$dep})); $dep .= " $V_REPO{$dep}\n$DESC{$dep}" if (($osearch{verbose}>1) and ($V_REPO{$dep}) and ($DESC{$dep})); } @@ -258,6 +259,9 @@ if (($#query < 0) and ($action =~ /^(install|update|depinst|remove)$/)) { print "$1 requires at least one argument.\n"; exit 1; } +if (($osearch{verbose} > 0) and ($action eq "dup")) { + push @query, "%n:\n%p1/%n %v1 > %p2/%n %v2"; +} return $action, @query; } @@ -613,7 +617,7 @@ sub list_ports { } if ($subset eq "orphans") { - my %not_orphans = map { $_ => 0 } @searchspace; + my %not_orphans = map { $_ => 0 } keys %V_INST; foreach my $port (@searchspace) { map { $not_orphans{$_} = 1 } split(/[ ,]+/, $DEPENDS{$port}); if (($odepends{soft} == 1) and ($SOFTDEPS{$port})) { @@ -623,7 +627,7 @@ sub list_ports { foreach my $al (keys %ALIASES) { $not_orphans{$al} = 1 if (($not_orphans{$ALIASES{$al}}) and ($not_orphans{$ALIASES{$al}} == 1)); } - @found = grep { $not_orphans{$_} == 0 } keys %V_INST; + @found = grep { ($not_orphans{$_} == 0) } keys %V_INST; } elsif (($subset eq "dependent") and ($odepends{recursive}==0)) { @found = grep { " $DEPENDS{$_} " =~ / $sseed / } @searchspace; if ($odepends{soft}==1) { @@ -811,7 +815,7 @@ sub up_inst { # returns scalar references to six arrays my @requested=@_; my @sortedList; my @targets; my %pdirs; my %builtpkg; my %mkcmd; my %addcmd; my $rs_cmd; my %logfile; my %pvars; my $status; my %ok; my @missing; my %not_ok; my %ok_pre; my %ok_post; my @ok_readme=(); - my $ord=0; my $PKGMK=$opkg{makecommand}; my $PKGADD=$opkg{addcommand}; + my $ord=0; my $PKGMK=$opkg{makecommand}; my $PKGADD; my $SH=$opkg{scriptcommand}; # resolve dependencies unless --nodeps was given, @@ -835,24 +839,24 @@ sub up_inst { # returns scalar references to six arrays @targets = grep {(! $LOCKED{$_})} @targets if ($opkg{nolock}==0); # first determine the directories from which pkgmk must be called, - # the package that will appear after a successful build, # and where to save the build log. - my ($COMPRESSION, $PKG_DIR) = parse_pkgmk_conf(); foreach my $t (@targets) { $opkg{$t} = $opkg{margs}; $pvars{'%n'}=$t; $opkg{$t} =~ s/-f// unless (grep /^$t$/, @requested); - $pvars{'%p'} = find_port_by_name($t,1,1,0); $pdirs{$t} = $pvars{'%p'}; + $pdirs{$t} = find_port_by_name($t,1,1,0); + $pvars{'%p'} = $pdirs{$t}; $pvars{'%v'} = $1 if ( $V_REPO{$t} =~ m/(.+)-[0-9]+$/ ); $pvars{'%r'} = $1 if ( $V_REPO{$t} =~ m/-([0-9]+)$/ ); - $builtpkg{$t} = ($PKG_DIR ne "") ? "$PKG_DIR/$t#$pvars{'%v'}-$pvars{'%r'}.pkg.tar.$COMPRESSION" : "$pvars{'%p'}/$t#$pvars{'%v'}-$pvars{'%r'}.pkg.tar.$COMPRESSION"; - $builtpkg{$t} =~ s/uuiName/$t/g; - $builtpkg{$t} =~ s/uuiVer/$pvars{'%v'}/g; - $builtpkg{$t} =~ s/uuiRel/$pvars{'%r'}/g; $mkcmd{$t} = "$PKGMK -d $opkg{$t}"; + $mkcmd{$t} .= ($V_INST{$t}) ? " -u" : " -i"; if (($altroot ne "") and ($opkg{aargs} !~ m/(-r|--root)/)) { - $opkg{aargs} .= " -r $altroot"; + $mkcmd{$t} .= " --install-root \"$altroot\""; } - $addcmd{$t} = "$PKGADD -u $opkg{aargs} $builtpkg{$t}"; + (! $opkg{addcommand}) or $PKGADD=$opkg{addcommand}; + if ($opkg{aargs}) { + ($PKGADD) ? $PKGADD .= " $opkg{aargs}" : $PKGADD = "/usr/bin/pkgadd $opkg{aargs}"; + } + $mkcmd{$t} .= " --addcommand \"$PKGADD\"" if ($PKGADD); if ($olog{write} eq "enabled") { $logfile{$t} = $olog{file}; $logfile{$t} =~ s/(%n|%v|%r|%p)/$pvars{$1}/g; @@ -866,10 +870,6 @@ sub up_inst { # returns scalar references to six arrays # build each package BUILDLOG: foreach my $t (@targets) { - if ( (-f $builtpkg{$t}) and ($opkg{$t} !~ /-f/) and - ((-M $builtpkg{$t}) > (-M "$pdirs{$t}/Pkgfile")) ) { - $mkcmd{$t} = "echo \"skipped build (package already exists)\""; - } if ($opkg{test} eq "yes") { ($mkcmd{$t} !~ /skipped/) or next BUILDLOG; print("$t"); @@ -897,16 +897,9 @@ sub up_inst { # returns scalar references to six arrays ($status) ? $ok{$t} = $ord : $not_ok{$t} = $ord; } if ($ok{$t}) { - $addcmd{$t} =~ s/ -u / / if (! $V_INST{$t}); - if (system("$addcmd{$t}")==0) { - push (@ok_readme, $t) if (-f "README"); - } else { - $not_ok{$t} = $ord; delete $ok{$t}; - } + push (@ok_readme, $t) if (-f "README"); unlink($logfile{$t}) if ( ($logfile{$t}) and ($olog{rm_on_success} eq "yes") ); - } elsif ( ($not_ok{$t}) and (-f "$builtpkg{$t}") ) { - rename("$builtpkg{$t}","$builtpkg{$t}.CHECKME"); } if (($ok{$t}) and ("$opkg{run_scripts} $opkg{post_install}" =~ /yes/) and (-f "$altroot$pdirs{$t}/post-install")) { $rs_cmd="$SH post-install"; @@ -928,22 +921,6 @@ sub up_inst { # returns scalar references to six arrays return \@ok, \%ok_pre, \%ok_post, \@ok_readme, \@not_ok, \@missing; } -sub parse_pkgmk_conf { - my @pkgmkVars; - my $heredoc = "bash -c 'name=uuiName; version=uuiVer;"; - $heredoc .= "release=uuiRel; source /etc/pkgmk.conf; "; - $heredoc .= "printf \"%s:%s\" \"\$PKGMK_PACKAGE_DIR\" "; - $heredoc .= "\$PKGMK_COMPRESSION_MODE;'"; - - open (CF,"-|",$heredoc) or return; - while () { @pkgmkVars = split /:/; - } close (CF); - - my $COMPRESSION = ($pkgmkVars[1]) ? $pkgmkVars[1] : "gz"; - my $PKGDIR = ($pkgmkVars[0]) ? $pkgmkVars[0] : ""; - return $COMPRESSION, $PKGDIR; -} - sub port_ls { my $port=shift; my $pp=find_port_by_name($port,1,1,0); return if (! defined $pp);