diff options
Diffstat (limited to 'scripts/repo-add.sh.in')
-rw-r--r-- | scripts/repo-add.sh.in | 255 |
1 files changed, 175 insertions, 80 deletions
diff --git a/scripts/repo-add.sh.in b/scripts/repo-add.sh.in index 02ab389c..b125035c 100644 --- a/scripts/repo-add.sh.in +++ b/scripts/repo-add.sh.in @@ -4,8 +4,7 @@ # repo-remove - remove a package entry from a given repo database file # @configure_input@ # -# Copyright (c) 2006-2008 Aaron Griffin <aaron@archlinux.org> -# Copyright (c) 2007-2008 Dan McGee <dan@archlinux.org> +# Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -21,7 +20,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # gettext initialization -export TEXTDOMAIN='pacman' +export TEXTDOMAIN='pacman-scripts' export TEXTDOMAINDIR='@localedir@' myver='@PACKAGE_VERSION@' @@ -30,6 +29,8 @@ confdir='@sysconfdir@' QUIET=0 DELTA=0 WITHFILES=0 +SIGN=0 +VERIFY=0 REPO_DB_FILE= LOCKFILE= CLEAN_LOCK=0 @@ -37,58 +38,46 @@ CLEAN_LOCK=0 # ensure we have a sane umask set umask 0022 -msg() { - (( QUIET )) && return - local mesg=$1; shift - printf "==> ${mesg}\n" "$@" >&1 -} - -msg2() { - (( QUIET )) && return - local mesg=$1; shift - printf " -> ${mesg}\n" "$@" >&1 -} - -warning() { - local mesg=$1; shift - printf "==> $(gettext "WARNING:") ${mesg}\n" "$@" >&2 -} - -error() { - local mesg=$1; shift - printf "==> $(gettext "ERROR:") ${mesg}\n" "$@" >&2 -} +m4_include(library/output_format.sh) # print usage instructions usage() { - printf "repo-add, repo-remove (pacman) %s\n\n" "$myver" - printf "$(gettext "Usage: repo-add [-d] [-f] [-q] <path-to-db> <package|delta> ...\n")" - printf "$(gettext "Usage: repo-remove [-q] <path-to-db> <packagename|delta> ...\n\n")" - printf "$(gettext "\ + cmd=${0##*/} + printf "%s (pacman) %s\n\n" "$cmd" "$myver" + if [[ $cmd == "repo-add" ]] ; then + printf "$(gettext "Usage: repo-add [options] <path-to-db> <package|delta> ...\n")" + printf "$(gettext "\ repo-add will update a package database by reading a package file.\n\ Multiple packages to add can be specified on the command line.\n\n")" - printf "$(gettext "\ + printf "$(gettext "Options:\n")" + printf "$(gettext " -d, --delta generate and add delta for package update\n")" + printf "$(gettext " -f, --files update database's file list\n")" + elif [[ $cmd == "repo-remove" ]] ; then + printf "$(gettext "Usage: repo-remove [options] <path-to-db> <packagename|delta> ...\n\n")" + printf "$(gettext "\ repo-remove will update a package database by removing the package name\n\ specified on the command line from the given repo database. Multiple\n\ packages to remove can be specified on the command line.\n\n")" - printf "$(gettext "\ -Use the -q/--quiet flag to minimize output to basic messages, warnings,\n\ -and errors.\n\n")" - printf "$(gettext "\ -Use the -d/--delta flag to automatically generate and add a delta file\n\ -between the old entry and the new one, if the old package file is found\n\ -next to the new one.\n\n")" - printf "$(gettext "\ -Use the -f/--files flag to update a database including file entries.\n\n")" - echo "$(gettext "Example: repo-add /path/to/repo.db.tar.gz pacman-3.0.0.pkg.tar.gz")" - echo "$(gettext "Example: repo-remove /path/to/repo.db.tar.gz kernel26")" + printf "$(gettext "Options:\n")" + fi + printf "$(gettext " -q, --quiet minimize output\n")" + printf "$(gettext " -s, --sign sign database with GnuPG after update\n")" + printf "$(gettext " -k, --key <key> use the specified key to sign the database\n")" + printf "$(gettext " -v, --verify verify database's signature before update\n")" + printf "$(gettext "\n\ +See %s(8) for more details and descriptions of the available options.\n\n")" $cmd + if [[ $cmd == "repo-add" ]] ; then + echo "$(gettext "Example: repo-add /path/to/repo.db.tar.gz pacman-3.0.0-1-i686.pkg.tar.gz")" + elif [[ $cmd == "repo-remove" ]] ; then + echo "$(gettext "Example: repo-remove /path/to/repo.db.tar.gz kernel26")" + fi } version() { - printf "repo-add, repo-remove (pacman) %s\n\n" "$myver" + cmd=${0##*/} + printf "%s (pacman) %s\n\n" "$cmd" "$myver" printf "$(gettext "\ -Copyright (C) 2006-2008 Aaron Griffin <aaron@archlinux.org>.\n\ -Copyright (c) 2007-2008 Dan McGee <dan@archlinux.org>.\n\n\ +Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>\n\n\ This is free software; see the source for copying conditions.\n\ There is NO WARRANTY, to the extent permitted by law.\n")" } @@ -104,8 +93,7 @@ write_list_entry() { fi } -find_pkgentry() -{ +find_pkgentry() { local pkgname=$1 local pkgentry for pkgentry in $tmpdir/$pkgname*; do @@ -128,8 +116,7 @@ get_delta_pkgname() { # write a delta entry # arg1 - path to delta file -db_write_delta() -{ +db_write_delta() { deltafile="$1" pkgname="$(get_delta_pkgname $deltafile)" @@ -161,8 +148,7 @@ db_write_delta() # remove a delta entry # arg1 - path to delta file -db_remove_delta() -{ +db_remove_delta() { deltafile="$1" filename=${deltafile##*/} pkgname="$(get_delta_pkgname $deltafile)" @@ -184,14 +170,61 @@ db_remove_delta() return 1 } # end db_remove_delta +check_gpg() { + if ! type -p gpg >/dev/null; then + error "$(gettext "Cannot find the gpg binary! Is gnupg installed?")" + exit 1 # $E_MISSING_PROGRAM + fi +} + +# sign the package database once repackaged +create_signature() { + (( ! SIGN )) && return + local dbfile="$1" + local ret=0 + msg "$(gettext "Signing database...")" + + local SIGNWITHKEY="" + if [[ -n $GPGKEY ]]; then + SIGNWITHKEY="-u ${GPGKEY}" + fi + gpg --detach-sign --use-agent ${SIGNWITHKEY} "$dbfile" &>/dev/null || ret=$? + + if (( ! ret )); then + msg2 "$(gettext "Created signature file %s.")" "$dbfile.sig" + else + warning "$(gettext "Failed to sign package database.")" + fi +} + +# verify the existing package database signature +verify_signature() { + (( ! VERIFY )) && return + local dbfile="$1" + local ret=0 + msg "$(gettext "Verifying database signature...")" + + if [[ ! -f $dbfile.sig ]]; then + warning "$(gettext "No existing signature found, skipping verification.")" + return + fi + gpg --verify "$dbfile.sig" || ret=$? + if (( ! ret )); then + msg2 "$(gettext "Database signature file verified.")" + else + error "$(gettext "Database signature was NOT valid!")" + exit 1 + fi +} + # write an entry to the pacman database # arg1 - path to package -db_write_entry() -{ +db_write_entry() { # blank out all variables local pkgfile="$1" - local pkgname pkgver pkgdesc csize size md5sum url arch builddate packager \ - _groups _licenses _replaces _depends _conflicts _provides _optdepends + local pkgname pkgver pkgdesc csize size url arch builddate packager \ + _groups _licenses _replaces _depends _conflicts _provides _optdepends \ + md5sum sha256sum pgpsig local OLDIFS="$IFS" # IFS (field separator) is only the newline character @@ -219,10 +252,19 @@ db_write_entry() IFS=$OLDIFS - # get md5sum and compressed size of package + csize=$(@SIZECMD@ "$pkgfile") + + # compute checksums + msg2 "$(gettext "Computing checksums...")" md5sum="$(openssl dgst -md5 "$pkgfile")" md5sum="${md5sum##* }" - csize=$(@SIZECMD@ "$pkgfile") + sha256sum="$(openssl dgst -sha256 "$pkgfile")" + sha256sum="${sha256sum##* }" + + # compute base64'd PGP signature + if [[ -f "$pkgfile.sig" ]]; then + pgpsig=$(openssl base64 -in "$pkgfile.sig" | tr -d '\n') + fi # ensure $pkgname and $pkgver variables were found if [[ -z $pkgname || -z $pkgver ]]; then @@ -255,7 +297,7 @@ db_write_entry() # create desc entry msg2 "$(gettext "Creating '%s' db entry...")" 'desc' - echo -e "%FILENAME%\n$(basename "$1")\n" >>desc + echo -e "%FILENAME%\n${1##*/}\n" >>desc echo -e "%NAME%\n$pkgname\n" >>desc [[ -n $pkgbase ]] && echo -e "%BASE%\n$pkgbase\n" >>desc echo -e "%VERSION%\n$pkgver\n" >>desc @@ -264,9 +306,12 @@ db_write_entry() [[ -n $csize ]] && echo -e "%CSIZE%\n$csize\n" >>desc [[ -n $size ]] && echo -e "%ISIZE%\n$size\n" >>desc - # compute checksums - msg2 "$(gettext "Computing md5 checksums...")" + # add checksums echo -e "%MD5SUM%\n$md5sum\n" >>desc + echo -e "%SHA256SUM%\n$sha256sum\n" >>desc + + # add PGP sig + [[ -n $pgpsig ]] && echo -e "%PGPSIG%\n$pgpsig\n" >>desc [[ -n $url ]] && echo -e "%URL%\n$url\n" >>desc write_list_entry "LICENSE" "$_licenses" "desc" @@ -324,15 +369,29 @@ db_remove_entry() { mv "$pkgentry/deltas" "$tmpdir/$pkgname.deltas" fi msg2 "$(gettext "Removing existing entry '%s'...")" \ - "$(basename $pkgentry)" + "${pkgentry##*/}" rm -rf $pkgentry pkgentry=$(find_pkgentry $pkgname) done return $notfound } # end db_remove_entry -check_repo_db() -{ +check_repo_db() { + local repodir + + # ensure the path to the DB exists + if [[ "$LOCKFILE" == /* ]]; then + repodir=${LOCKFILE%/*}/ + else + repodir=$PWD/$LOCKFILE + repodir=${repodir%/*}/ + fi + + if [[ ! -d "$repodir" ]]; then + error "$(gettext "%s does not exist or is not a directory.")" "$repodir" + exit 1 + fi + # check lock file if ( set -o noclobber; echo "$$" > "$LOCKFILE") 2> /dev/null; then CLEAN_LOCK=1 @@ -352,6 +411,7 @@ check_repo_db() exit 1 fi fi + verify_signature "$REPO_DB_FILE" msg "$(gettext "Extracting database to a temporary location...")" bsdtar -xf "$REPO_DB_FILE" -C "$tmpdir" else @@ -372,8 +432,7 @@ check_repo_db() fi } -add() -{ +add() { if [[ ! -f $1 ]]; then error "$(gettext "File '%s' not found.")" "$1" return 1 @@ -404,8 +463,7 @@ add() db_write_entry "$pkgfile" } -remove() -{ +remove() { if [[ ${1##*.} == "delta" ]]; then deltafile=$1 msg "$(gettext "Searching for delta '%s'...")" "$deltafile" @@ -429,8 +487,7 @@ remove() fi } -trap_exit() -{ +trap_exit() { echo error "$@" exit 1 @@ -460,7 +517,7 @@ case "$1" in esac # figure out what program we are -cmd="$(basename $0)" +cmd=${0##*/} if [[ $cmd != "repo-add" && $cmd != "repo-remove" ]]; then error "$(gettext "Invalid command name '%s' specified.")" "$cmd" exit 1 @@ -477,24 +534,50 @@ trap 'trap_exit "$(gettext "An unknown error has occured. Exiting...")"' ERR success=0 # parse arguments -for arg in "$@"; do - case "$arg" in +while [[ $# > 0 ]]; do + case "$1" in -q|--quiet) QUIET=1;; -d|--delta) DELTA=1;; -f|--files) WITHFILES=1;; + -s|--sign) + check_gpg + SIGN=1 + if ! gpg --list-key ${GPGKEY} &>/dev/null; then + if [[ ! -z $GPGKEY ]]; then + error "$(gettext "The key ${GPGKEY} does not exist in your keyring.")" + else + error "$(gettext "There is no key in your keyring.")" + fi + exit 1 + fi + ;; + -k|--key) + check_gpg + shift + GPGKEY="$1" + if ! gpg --list-key ${GPGKEY} &>/dev/null; then + error "$(gettext "The key ${GPGKEY} does not exist in your keyring.")" + exit 1 + fi + ;; + -v|--verify) + check_gpg + VERIFY=1 + ;; *) if [[ -z $REPO_DB_FILE ]]; then - REPO_DB_FILE="$arg" + REPO_DB_FILE="$1" LOCKFILE="$REPO_DB_FILE.lck" check_repo_db else case "$cmd" in - repo-add) add $arg && success=1 ;; - repo-remove) remove $arg && success=1 ;; + repo-add) add $1 && success=1 ;; + repo-remove) remove $1 && success=1 ;; esac fi ;; esac + shift done # if at least one operation was a success, re-zip database @@ -502,14 +585,15 @@ if (( success )); then msg "$(gettext "Creating updated database file '%s'")" "$REPO_DB_FILE" case "$REPO_DB_FILE" in - *tar.gz) TAR_OPT="z" ;; - *tar.bz2) TAR_OPT="j" ;; - *tar.xz) TAR_OPT="J" ;; + *.tar.gz) TAR_OPT="z" ;; + *.tar.bz2) TAR_OPT="j" ;; + *.tar.xz) TAR_OPT="J" ;; + *.tar) TAR_OPT="" ;; *) warning "$(gettext "'%s' does not have a valid archive extension.")" \ "$REPO_DB_FILE" ;; esac - filename=$(basename "$REPO_DB_FILE") + filename=${REPO_DB_FILE##*/} pushd "$tmpdir" >/dev/null if [[ -n $(ls) ]]; then @@ -519,15 +603,26 @@ if (( success )); then warning "$(gettext "No packages remain, creating empty database.")" bsdtar -c${TAR_OPT}f "$filename" -T /dev/null fi + create_signature "$filename" + popd >/dev/null [[ -f $REPO_DB_FILE ]] && mv -f "$REPO_DB_FILE" "${REPO_DB_FILE}.old" + [[ -f $REPO_DB_FILE.sig ]] && rm -f "$REPO_DB_FILE.sig" [[ -f $tmpdir/$filename ]] && mv "$tmpdir/$filename" "$REPO_DB_FILE" - dblink="${REPO_DB_FILE%.tar.*}" + [[ -f $tmpdir/$filename.sig ]] && mv "$tmpdir/$filename.sig" "$REPO_DB_FILE.sig" + dblink="${REPO_DB_FILE%.tar*}" target=${REPO_DB_FILE##*/} - ln -sf "$target" "$dblink" 2>/dev/null || \ - ln -f "$target" "$dblink" 2>/dev/null || \ + rm -f "$dblink" + ln -s "$target" "$dblink" 2>/dev/null || \ + ln "$target" "$dblink" 2>/dev/null || \ cp "$REPO_DB_FILE" "$dblink" + if [[ -f "$target.sig" ]]; then + rm -f "$dblink.sig" + ln -s "$target.sig" "$dblink.sig" 2>/dev/null || \ + ln "$target.sig" "$dblink.sig" 2>/dev/null || \ + cp "$REPO_DB_FILE.sig" "$dblink.sig" + fi else msg "$(gettext "No packages modified, nothing to do.")" exit 1 |