From 8679cd68d825bfe28ba0c833494c415bcfa6d8f6 Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Sun, 8 Apr 2012 12:32:17 -0400 Subject: scripts/library: introduce parseopts This will replace our current options parser used in pacman-key, makepkg, and ideally elsewhere. It follows heuristics closer to that of GNU getopt long (and thus pacman itself), with the exception that it does not allow for options with optional arguments. Due to the way this parser will be used, this sort of functionality will not be needed. Instead of relying on eval+set, options are normalized into an array, OPTRET, which callers should expect to be populated after returning from parseopts. This avoids problems with quotes and spaces in arguments, assuming that the user quotes properly when passing into the application. A new test harness for parseopts is added in test/scripts. Signed-off-by: Dave Reisner --- scripts/Makefile.am | 1 + scripts/library/README | 20 ++++++ scripts/library/parseopts.sh | 141 +++++++++++++++++++++++++++++++++++++++++++ scripts/po/POTFILES.in | 1 + 4 files changed, 163 insertions(+) create mode 100644 scripts/library/parseopts.sh (limited to 'scripts') diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 328fbff2..7662fba6 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -27,6 +27,7 @@ EXTRA_DIST = \ LIBRARY = \ library/output_format.sh \ + library/parseopts.sh \ library/parse_options.sh # Files that should be removed, but which Automake does not know. diff --git a/scripts/library/README b/scripts/library/README index 1e9c962b..f43873f3 100644 --- a/scripts/library/README +++ b/scripts/library/README @@ -13,3 +13,23 @@ A getopt replacement to avoids portability issues, in particular the lack of long option name support in the default getopt provided by some platforms. Usage: parse_option $SHORT_OPTS $LONG_OPTS "$@" + +parseopts.sh: +A getopt_long-like parser which portably supports longopts and shortopts +with some GNU extensions. It does not allow for options with optional +arguments. For both short and long opts, options requiring an argument +should be suffixed with a colon. After the first argument containing +the short opts, any number of valid long opts may be be passed. The end +of the options delimiter must then be added, followed by the user arguments +to the calling program. + +Reccommended Usage: + OPT_SHORT='fb:z' + OPT_LONG=('foo' 'bar:' 'baz') + if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then + exit 1 + fi + set -- "${OPTRET[@]}" +Returns: + 0: parse success + 1: parse failure (error message supplied) diff --git a/scripts/library/parseopts.sh b/scripts/library/parseopts.sh new file mode 100644 index 00000000..11589ce3 --- /dev/null +++ b/scripts/library/parseopts.sh @@ -0,0 +1,141 @@ +# getopt-like parser +parseopts() { + local opt= optarg= i= shortopts=$1 + local -a longopts=() unused_argv=() + + shift + while [[ $1 && $1 != '--' ]]; do + longopts+=("$1") + shift + done + shift + + longoptmatch() { + local o longmatch=() + for o in "${longopts[@]}"; do + if [[ ${o%:} = "$1" ]]; then + longmatch=("$o") + break + fi + [[ ${o%:} = "$1"* ]] && longmatch+=("$o") + done + + case ${#longmatch[*]} in + 1) + # success, override with opt and return arg req (0 == none, 1 == required) + opt=${longmatch%:} + if [[ $longmatch = *: ]]; then + return 1 + else + return 0 + fi ;; + 0) + # fail, no match found + return 255 ;; + *) + # fail, ambiguous match + printf "@SCRIPTNAME@: $(gettext "option '%s' is ambiguous; possibilities:")" "--$1" + printf " '%s'" "${longmatch[@]%:}" + printf '\n' + return 254 ;; + esac >&2 + } + + while (( $# )); do + case $1 in + --) # explicit end of options + shift + break + ;; + -[!-]*) # short option + for (( i = 1; i < ${#1}; i++ )); do + opt=${1:i:1} + + # option doesn't exist + if [[ $shortopts != *$opt* ]]; then + printf "@SCRIPTNAME@: $(gettext "invalid option") -- '%s'\n" "$opt" >&2 + OPTRET=(--) + return 1 + fi + + OPTRET+=("-$opt") + # option requires optarg + if [[ $shortopts = *$opt:* ]]; then + # if we're not at the end of the option chunk, the rest is the optarg + if (( i < ${#1} - 1 )); then + OPTRET+=("${1:i+1}") + break + # if we're at the end, grab the the next positional, if it exists + elif (( i == ${#1} - 1 )) && [[ $2 ]]; then + OPTRET+=("$2") + shift + break + # parse failure + else + printf "@SCRIPTNAME@: $(gettext "option requires an argument") -- '%s'\n" "$opt" >&2 + OPTRET=(--) + return 1 + fi + fi + done + ;; + --?*=*|--?*) # long option + IFS='=' read -r opt optarg <<< "${1#--}" + longoptmatch "$opt" + case $? in + 0) + # parse failure + if [[ $optarg ]]; then + printf "@SCRIPTNAME@: $(gettext "option '%s' does not allow an argument")\n" "--$opt" >&2 + OPTRET=(--) + return 1 + # --longopt + else + OPTRET+=("--$opt") + shift + continue 2 + fi + ;; + 1) + # --longopt=optarg + if [[ $optarg ]]; then + OPTRET+=("--$opt" "$optarg") + shift + # --longopt optarg + elif [[ $2 ]]; then + OPTRET+=("--$opt" "$2" ) + shift 2 + # parse failure + else + printf "@SCRIPTNAME@: $(gettext "option '%s' requires an argument")\n" "--$opt" >&2 + OPTRET=(--) + return 1 + fi + continue 2 + ;; + 254) + # ambiguous option -- error was reported for us by longoptmatch() + OPTRET=(--) + return 1 + ;; + 255) + # parse failure + printf "@SCRIPTNAME@: $(gettext "invalid option") '--%s'\n" "$opt" >&2 + OPTRET=(--) + return 1 + ;; + esac + ;; + *) # non-option arg encountered, add it as a parameter + unused_argv+=("$1") + ;; + esac + shift + done + + # add end-of-opt terminator and any leftover positional parameters + OPTRET+=('--' "${unused_argv[@]}" "$@") + unset longoptmatch + + return 0 +} diff --git a/scripts/po/POTFILES.in b/scripts/po/POTFILES.in index 007e535f..01cc235f 100644 --- a/scripts/po/POTFILES.in +++ b/scripts/po/POTFILES.in @@ -9,3 +9,4 @@ scripts/pkgdelta.sh.in scripts/repo-add.sh.in scripts/library/output_format.sh scripts/library/parse_options.sh +scripts/library/parseopts.sh -- cgit v1.2.3-24-g4f1b From d85c71865ee826041c85cd47189ea43b44ce52cc Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Sun, 8 Apr 2012 13:13:07 -0400 Subject: makepkg: adopt parseopts for option parsing Signed-off-by: Dave Reisner --- scripts/Makefile.am | 2 +- scripts/makepkg.sh.in | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'scripts') diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 7662fba6..0df90e13 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -68,7 +68,7 @@ $(OURSCRIPTS): Makefile makepkg: \ $(srcdir)/makepkg.sh.in \ - $(srcdir)/library/parse_options.sh + $(srcdir)/library/parseopts.sh pacman-db-upgrade: \ $(srcdir)/pacman-db-upgrade.sh.in \ diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index 46191ee4..663fdc68 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -1885,7 +1885,7 @@ canonicalize_path() { fi } -m4_include(library/parse_options.sh) +m4_include(library/parseopts.sh) usage() { printf "makepkg (pacman) %s\n" "$myver" @@ -1954,19 +1954,20 @@ ARGLIST=("$@") # Parse Command Line Options. OPT_SHORT="AcdefFghiLmop:rRsSV" -OPT_LONG="allsource,asroot,ignorearch,check,clean,nodeps" -OPT_LONG+=",noextract,force,forcever:,geninteg,help,holdver,skippgpcheck" -OPT_LONG+=",install,key:,log,nocolor,nobuild,nocheck,nosign,pkg:,rmdeps" -OPT_LONG+=",repackage,skipchecksums,skipinteg,skippgpcheck,sign,source,syncdeps" -OPT_LONG+=",version,config:" +OPT_LONG=('allsource' 'asroot' 'ignorearch' 'check' 'clean' 'nodeps' + 'noextract' 'force' 'forcever:' 'geninteg' 'help' 'holdver' 'skippgpcheck' + 'install' 'key:' 'log' 'nocolor' 'nobuild' 'nocheck' 'nosign' 'pkg:' 'rmdeps' + 'repackage' 'skipchecksums' 'skipinteg' 'skippgpcheck' 'sign' 'source' 'syncdeps' + 'version' 'config:') # Pacman Options -OPT_LONG+=",noconfirm,noprogressbar" -if ! OPT_TEMP="$(parse_options $OPT_SHORT $OPT_LONG "$@")"; then +OPT_LONG+=('noconfirm' 'noprogressbar') + +if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then echo; usage; exit 1 # E_INVALID_OPTION; fi -eval set -- "$OPT_TEMP" -unset OPT_SHORT OPT_LONG OPT_TEMP +set -- "${OPTRET[@]}" +unset OPT_SHORT OPT_LONG OPTRET while true; do case "$1" in @@ -1997,7 +1998,7 @@ while true; do --nosign) SIGNPKG='n' ;; -o|--nobuild) NOBUILD=1 ;; -p) shift; BUILDFILE=$1 ;; - --pkg) shift; PKGLIST=($1) ;; + --pkg) shift; IFS=, read -ra PKGLIST <<<"$1" ;; -r|--rmdeps) RMDEPS=1 ;; -R|--repackage) REPKG=1 ;; --skipchecksums) SKIPCHECKSUMS=1 ;; @@ -2010,8 +2011,7 @@ while true; do -h|--help) usage; exit 0 ;; # E_OK -V|--version) version; exit 0 ;; # E_OK - --) OPT_IND=0; shift; break;; - *) usage; exit 1 ;; # E_INVALID_OPTION + --) OPT_IND=0; shift; break 2;; esac shift done -- cgit v1.2.3-24-g4f1b From 3f9cf8471f9c6faecba8e09deb97a8d042525307 Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Sun, 8 Apr 2012 13:26:41 -0400 Subject: makepkg: allow specifying --pkg multiple times Make this option additive, so that the following two operations are equivalent: makepkg --pkg foo --pkg bar makepkg --pkg foo,bar --- scripts/makepkg.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'scripts') diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index 663fdc68..959c6b00 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -1998,7 +1998,7 @@ while true; do --nosign) SIGNPKG='n' ;; -o|--nobuild) NOBUILD=1 ;; -p) shift; BUILDFILE=$1 ;; - --pkg) shift; IFS=, read -ra PKGLIST <<<"$1" ;; + --pkg) shift; IFS=, read -ra p <<<"$1"; PKGLIST+=("${p[@]}"); unset p ;; -r|--rmdeps) RMDEPS=1 ;; -R|--repackage) REPKG=1 ;; --skipchecksums) SKIPCHECKSUMS=1 ;; -- cgit v1.2.3-24-g4f1b From f61f075b1cd4c226d1633abd383565934bea2f0d Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Sun, 8 Apr 2012 14:51:28 -0400 Subject: pacman-key: adopt parseopts for option parsing This requires an ugly amount of reworking of how pacman-key handles options. The change simply to avoid passing keys, files, and directories as arguments to options, but to leave them as arguments to the overall program. This is reasonable since pacman-key limits the user to essentially one operation per invocation (like pacman). Since we now pass around the positional parameters to the various operations, we can add some better sanity checking. Each operation is responsible for testing input and making sure it can operate properly, otherwise it throws an error and exits. The doc is updated to reflect this, and uses similar verbiage as pacman, describing the non-option arguments now passed to pacman-key as targets. Similar to the doc, --help is reorganized to separate operations and options and remove argument tokens from operations. Signed-off-by: Dave Reisner --- scripts/Makefile.am | 2 +- scripts/pacman-key.sh.in | 179 +++++++++++++++++++++++++---------------------- 2 files changed, 95 insertions(+), 86 deletions(-) (limited to 'scripts') diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 0df90e13..fc70732f 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -77,7 +77,7 @@ pacman-db-upgrade: \ pacman-key: \ $(srcdir)/pacman-key.sh.in \ $(srcdir)/library/output_format.sh \ - $(srcdir)/library/parse_options.sh + $(srcdir)/library/parseopts.sh pacman-optimize: \ $(srcdir)/pacman-optimize.sh.in \ diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index 288b76eb..2ee05c51 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -49,40 +49,43 @@ DEFAULT_KEYSERVER='hkp://pool.sks-keyservers.net' m4_include(library/output_format.sh) -m4_include(library/parse_options.sh) +m4_include(library/parseopts.sh) usage() { printf "pacman-key (pacman) %s\n" ${myver} echo - printf -- "$(gettext "Usage: %s [options]")\n" $(basename $0) + printf -- "$(gettext "Usage: %s [options] operation [targets]")\n" $(basename $0) echo printf -- "$(gettext "Manage pacman's list of trusted keys")\n" echo - printf -- "$(gettext "Options:")\n" - printf -- "$(gettext " -a, --add [file(s)] Add the specified keys (empty for stdin)")\n" - printf -- "$(gettext " -d, --delete Remove the specified keyids")\n" - printf -- "$(gettext " -e, --export [keyid(s)] Export the specified or all keyids")\n" - printf -- "$(gettext " -f, --finger [keyid(s)] List fingerprint for specified or all keyids")\n" - printf -- "$(gettext " -h, --help Show this help message and exit")\n" - printf -- "$(gettext " -l, --list-keys [keyid(s)] List the specified or all keys")\n" - printf -- "$(gettext " -r, --recv-keys Fetch the specified keyids")\n" + printf -- "$(gettext "Operations:")\n" + printf -- "$(gettext " -a, --add Add the specified keys (empty for stdin)")\n" + printf -- "$(gettext " -d, --delete Remove the specified keyids")\n" + printf -- "$(gettext " -e, --export Export the specified or all keyids")\n" + printf -- "$(gettext " -f, --finger List fingerprint for specified or all keyids")\n" + printf -- "$(gettext " -l, --list-keys List the specified or all keys")\n" + printf -- "$(gettext " -r, --recv-keys Fetch the specified keyids")\n" printf -- "$(gettext " -u, --updatedb Update the trustdb of pacman")\n" - printf -- "$(gettext " -v, --verify Verify the file specified by the signature")\n" - printf -- "$(gettext " -V, --version Show program version")\n" + printf -- "$(gettext " -v, --verify Verify the file specified by the signature")\n" + printf -- "$(gettext " --edit-key Present a menu for key management task on keyids")\n" + printf -- "$(gettext " --import Imports pubring.gpg from dir(s)")\n" + printf -- "$(gettext " --import-trustdb Imports ownertrust values from trustdb.gpg in dir(s)")\n" + printf -- "$(gettext " --init Ensure the keyring is properly initialized")\n" + printf -- "$(gettext " --list-sigs List keys and their signatures")\n" + printf -- "$(gettext " --lsign-key Locally sign the specified keyid")\n" + printf -- "$(gettext " --populate Reload the default keys from the (given) keyrings\n\ + in '%s'")\n" "@pkgdatadir@/keyrings" + printf -- "$(gettext " --refresh-keys Update specified or all keys from a keyserver")\n" + echo + printf -- "$(gettext "Options:")\n" printf -- "$(gettext " --config Use an alternate config file (instead of\n\ '%s')")\n" "@sysconfdir@/pacman.conf" - printf -- "$(gettext " --edit-key Present a menu for key management task on keyids")\n" printf -- "$(gettext " --gpgdir Set an alternate directory for GnuPG (instead\n\ of '%s')")\n" "@sysconfdir@/pacman.d/gnupg" - printf -- "$(gettext " --import Imports pubring.gpg from dir(s)")\n" - printf -- "$(gettext " --import-trustdb Imports ownertrust values from trustdb.gpg in dir(s)")\n" - printf -- "$(gettext " --init Ensure the keyring is properly initialized")\n" - printf -- "$(gettext " --keyserver Specify a keyserver to use if necessary")\n" - printf -- "$(gettext " --list-sigs [keyid(s)] List keys and their signatures")\n" - printf -- "$(gettext " --lsign-key Locally sign the specified keyid")\n" - printf -- "$(gettext " --populate [keyring(s)] Reload the default keys from the (given) keyrings\n\ - in '%s'")\n" "@pkgdatadir@/keyrings" - printf -- "$(gettext " --refresh-keys [keyid(s)] Update specified or all keys from a keyserver")\n" + printf -- "$(gettext " --keyserver Specify a keyserver to use if necessary")\n" + echo + printf -- "$(gettext " -h, --help Show this help message and exit")\n" + printf -- "$(gettext " -V, --version Show program version")\n" } version() { @@ -146,7 +149,7 @@ add_gpg_conf_option() { check_keyids_exist() { local ret=0 - for key in "${KEYIDS[@]}"; do + for key in "$@"; do # Verify if the key exists in pacman's keyring if ! "${GPG_PACMAN[@]}" --list-keys "$key" &>/dev/null ; then error "$(gettext "The key identified by %s could not be found locally.")" "$key" @@ -217,16 +220,16 @@ check_keyring() { populate_keyring() { local KEYRING_IMPORT_DIR='@pkgdatadir@/keyrings' - local keyring + local keyring KEYRINGIDS=("$@") local ret=0 - if [[ -z ${KEYRINGIDS[@]} ]]; then + if (( ${#KEYRINGIDS[*]} == 0 )); then # get list of all available keyrings shopt -s nullglob KEYRINGIDS=("$KEYRING_IMPORT_DIR"/*.gpg) shopt -u nullglob KEYRINGIDS=("${KEYRINGIDS[@]##*/}") KEYRINGIDS=("${KEYRINGIDS[@]%.gpg}") - if [[ -z ${KEYRINGIDS[@]} ]]; then + if (( ${#KEYRINGIDS[*]} == 0 )); then error "$(gettext "No keyring files exist in %s.")" "$KEYRING_IMPORT_DIR" ret=1 fi @@ -311,24 +314,24 @@ populate_keyring() { } add_keys() { - if ! "${GPG_PACMAN[@]}" --quiet --batch --import "${KEYFILES[@]}" ; then + if ! "${GPG_PACMAN[@]}" --quiet --batch --import "$@" ; then error "$(gettext "A specified keyfile could not be added to the gpg keychain.")" exit 1 fi } delete_keys() { - check_keyids_exist - if ! "${GPG_PACMAN[@]}" --quiet --batch --delete-key --yes "${KEYIDS[@]}" ; then + check_keyids_exist "$@" + if ! "${GPG_PACMAN[@]}" --quiet --batch --delete-key --yes "$@" ; then error "$(gettext "A specified key could not be removed from the gpg keychain.")" exit 1 fi } edit_keys() { - check_keyids_exist + check_keyids_exist "$@" local ret=0 - for key in "${KEYIDS[@]}"; do + for key in "$@"; do if ! "${GPG_PACMAN[@]}" --edit-key "$key" ; then error "$(gettext "The key identified by %s could not be edited.")" "$key" ret=1 @@ -340,8 +343,8 @@ edit_keys() { } export_keys() { - check_keyids_exist - if ! "${GPG_PACMAN[@]}" --armor --export "${KEYIDS[@]}" ; then + check_keyids_exist "$@" + if ! "${GPG_PACMAN[@]}" --armor --export "$@" ; then error "$(gettext "A specified key could not be exported from the gpg keychain.")" exit 1 fi @@ -349,7 +352,7 @@ export_keys() { finger_keys() { check_keyids_exist - if ! "${GPG_PACMAN[@]}" --batch --fingerprint "${KEYIDS[@]}" ; then + if ! "${GPG_PACMAN[@]}" --batch --fingerprint "$@" ; then error "$(gettext "The fingerprint of a specified key could not be determined.")" exit 1 fi @@ -358,7 +361,7 @@ finger_keys() { import_trustdb() { local importdir local ret=0 - for importdir in "${IMPORT_DIRS[@]}"; do + for importdir in "$@"; do if [[ -f "${importdir}/trustdb.gpg" ]]; then gpg --homedir "${importdir}" --export-ownertrust | \ "${GPG_PACMAN[@]}" --import-ownertrust - @@ -379,7 +382,7 @@ import_trustdb() { import() { local importdir local ret=0 - for importdir in "${IMPORT_DIRS[@]}"; do + for importdir in "$@"; do if [[ -f "${importdir}/pubring.gpg" ]]; then if ! "${GPG_PACMAN[@]}" --quiet --batch --import "${importdir}/pubring.gpg" ; then error "$(gettext "%s could not be imported.")" "${importdir}/pubring.gpg" @@ -397,7 +400,7 @@ import() { list_keys() { check_keyids_exist - if ! "${GPG_PACMAN[@]}" --batch --list-keys "${KEYIDS[@]}" ; then + if ! "${GPG_PACMAN[@]}" --batch --list-keys "$@" ; then error "$(gettext "A specified key could not be listed.")" exit 1 fi @@ -405,7 +408,7 @@ list_keys() { list_sigs() { check_keyids_exist - if ! "${GPG_PACMAN[@]}" --batch --list-sigs "${KEYIDS[@]}" ; then + if ! "${GPG_PACMAN[@]}" --batch --list-sigs "$@" ; then error "$(gettext "A specified signature could not be listed.")" exit 1 fi @@ -413,7 +416,7 @@ list_sigs() { lsign_keys() { check_keyids_exist - printf 'y\ny\n' | LANG=C "${GPG_PACMAN[@]}" --command-fd 0 --quiet --batch --lsign-key "${KEYIDS[@]}" 2>/dev/null + printf 'y\ny\n' | LANG=C "${GPG_PACMAN[@]}" --command-fd 0 --quiet --batch --lsign-key "$@" 2>/dev/null if (( PIPESTATUS[1] )); then error "$(gettext "A specified key could not be locally signed.")" exit 1 @@ -421,23 +424,23 @@ lsign_keys() { } receive_keys() { - if ! "${GPG_PACMAN[@]}" --recv-keys "${KEYIDS[@]}" ; then + if ! "${GPG_PACMAN[@]}" --recv-keys "$@" ; then error "$(gettext "Remote key not fetched correctly from keyserver.")" exit 1 fi } refresh_keys() { - check_keyids_exist - if ! "${GPG_PACMAN[@]}" --refresh-keys "${KEYIDS[@]}" ; then + check_keyids_exist "$@" + if ! "${GPG_PACMAN[@]}" --refresh-keys "$@" ; then error "$(gettext "A specified local key could not be updated from a keyserver.")" exit 1 fi } verify_sig() { - if ! "${GPG_PACMAN[@]}" --status-fd 1 --verify $SIGNATURE | grep -qE 'TRUST_(FULLY|ULTIMATE)'; then - error "$(gettext "The signature identified by %s could not be verified.")" "$SIGNATURE" + if ! "${GPG_PACMAN[@]}" --status-fd 1 --verify "$1" | grep -qE 'TRUST_(FULLY|ULTIMATE)'; then + error "$(gettext "The signature identified by %s could not be verified.")" "$1" exit 1 fi } @@ -457,56 +460,55 @@ if ! type gettext &>/dev/null; then } fi -OPT_SHORT="a::d:e::f::hl::r:uv:V" -OPT_LONG="add::,config:,delete:,edit-key:,export::,finger::,gpgdir:" -OPT_LONG+=",help,import:,import-trustdb:,init,keyserver:,list-keys::,list-sigs::" -OPT_LONG+=",lsign-key:,populate::,recv-keys:,refresh-keys::,updatedb" -OPT_LONG+=",verify:,version" -if ! OPT_TEMP="$(parse_options $OPT_SHORT $OPT_LONG "$@")"; then +OPT_SHORT="adefhlruvV" +OPT_LONG=('add' 'config:' 'delete' 'edit-key' 'export' 'finger' 'gpgdir:' + 'help' 'import' 'import-trustdb' 'init' 'keyserver:' 'list-keys' 'list-sigs' + 'lsign-key' 'populate' 'recv-keys' 'refresh-keys' 'updatedb' + 'verify' 'version') +if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then echo; usage; exit 1 # E_INVALID_OPTION; fi -eval set -- "$OPT_TEMP" -unset OPT_SHORT OPT_LONG OPT_TEMP +set -- "${OPTRET[@]}" +unset OPT_SHORT OPT_LONG OPTRET if [[ $1 == "--" ]]; then usage; exit 0; fi -while true; do - case "$1" in - -a|--add) ADD=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYFILES=($1); UPDATEDB=1 ;; +while (( $# )); do + case $1 in + -a|--add) ADD=1 UPDATEDB=1 ;; --config) shift; CONFIG=$1 ;; - -d|--delete) DELETE=1; shift; KEYIDS=($1); UPDATEDB=1 ;; - --edit-key) EDITKEY=1; shift; KEYIDS=($1); UPDATEDB=1 ;; - -e|--export) EXPORT=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; - -f|--finger) FINGER=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; + -d|--delete) DELETE=1 UPDATEDB=1 ;; + --edit-key) EDITKEY=1 UPDATEDB=1 ;; + -e|--export) EXPORT=1 ;; + -f|--finger) FINGER=1 ;; --gpgdir) shift; PACMAN_KEYRING_DIR=$1 ;; - --import) IMPORT=1; shift; IMPORT_DIRS=($1); UPDATEDB=1 ;; - --import-trustdb) IMPORT_TRUSTDB=1; shift; IMPORT_DIRS=($1); UPDATEDB=1 ;; + --import) IMPORT=1 UPDATEDB=1 ;; + --import-trustdb) IMPORT_TRUSTDB=1 UPDATEDB=1 ;; --init) INIT=1 ;; --keyserver) shift; KEYSERVER=$1 ;; - -l|--list-keys) LISTKEYS=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; - --list-sigs) LISTSIGS=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; - --lsign-key) LSIGNKEY=1; shift; KEYIDS=($1); UPDATEDB=1 ;; - --populate) POPULATE=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYRINGIDS=($1); UPDATEDB=1 ;; - -r|--recv-keys) RECEIVE=1; shift; KEYIDS=($1); UPDATEDB=1 ;; - --refresh-keys) REFRESH=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; + -l|--list-keys) LISTKEYS=1 ;; + --list-sigs) LISTSIGS=1 ;; + --lsign-key) LSIGNKEY=1 UPDATEDB=1 ;; + --populate) POPULATE=1 UPDATEDB=1 ;; + -r|--recv-keys) RECEIVE=1 UPDATEDB=1 ;; + --refresh-keys) REFRESH=1 ;; -u|--updatedb) UPDATEDB=1 ;; - -v|--verify) VERIFY=1; shift; SIGNATURE=$1 ;; + -v|--verify) VERIFY=1 ;; -h|--help) usage; exit 0 ;; -V|--version) version; exit 0 ;; - --) OPT_IND=0; shift; break;; - *) usage; exit 1 ;; + --) shift; break 2 ;; esac shift done if ! type -p gpg >/dev/null; then - error "$(gettext "Cannot find the %s binary required for all %s operations.")" "gpg" "pacman-key" + error "$(gettext "Cannot find the %s binary required for all %s operations.")" "gpg" "pacman-key" exit 1 fi @@ -549,23 +551,30 @@ case $numopt in ;; esac +# check for targets where needed +if (( (ADD || DELETE || EDIT || IMPORT || IMPORT_TRUSTDB || + LSIGNKEY || RECEIVE || VERIFY) && $# == 0 )); then + error "$(gettext "No targets specified")" + exit 1 +fi + (( ! INIT )) && check_keyring -(( ADD )) && add_keys -(( DELETE )) && delete_keys -(( EDITKEY )) && edit_keys -(( EXPORT )) && export_keys -(( FINGER )) && finger_keys -(( IMPORT )) && import -(( IMPORT_TRUSTDB)) && import_trustdb +(( ADD )) && add_keys "$@" +(( DELETE )) && delete_keys "$@" +(( EDITKEY )) && edit_keys "$@" +(( EXPORT )) && export_keys "$@" +(( FINGER )) && finger_keys "$@" +(( IMPORT )) && import "$@" +(( IMPORT_TRUSTDB)) && import_trustdb "$@" (( INIT )) && initialize -(( LISTKEYS )) && list_keys -(( LISTSIGS )) && list_sigs -(( LSIGNKEY )) && lsign_keys -(( POPULATE )) && populate_keyring -(( RECEIVE )) && receive_keys -(( REFRESH )) && refresh_keys -(( VERIFY )) && verify_sig +(( LISTKEYS )) && list_keys "$@" +(( LISTSIGS )) && list_sigs "$@" +(( LSIGNKEY )) && lsign_keys "$@" +(( POPULATE )) && populate_keyring "$@" +(( RECEIVE )) && receive_keys "$@" +(( REFRESH )) && refresh_keys "$@" +(( VERIFY )) && verify_sig "$@" (( UPDATEDB )) && updatedb -- cgit v1.2.3-24-g4f1b From 62dbf7ec43f4420c20b78ec647594c3f63558a39 Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Tue, 17 Apr 2012 00:27:37 -0400 Subject: scripts: avoid dumping usage on parser fail Avoid letting the error message from parseopts get lost in the usage output from pacman-key and makepkg (which is already verbose). --- scripts/makepkg.sh.in | 2 +- scripts/pacman-key.sh.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'scripts') diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index 959c6b00..8b3c80ce 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -1964,7 +1964,7 @@ OPT_LONG=('allsource' 'asroot' 'ignorearch' 'check' 'clean' 'nodeps' OPT_LONG+=('noconfirm' 'noprogressbar') if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then - echo; usage; exit 1 # E_INVALID_OPTION; + exit 1 # E_INVALID_OPTION; fi set -- "${OPTRET[@]}" unset OPT_SHORT OPT_LONG OPTRET diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index 2ee05c51..75564930 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -466,7 +466,7 @@ OPT_LONG=('add' 'config:' 'delete' 'edit-key' 'export' 'finger' 'gpgdir:' 'lsign-key' 'populate' 'recv-keys' 'refresh-keys' 'updatedb' 'verify' 'version') if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then - echo; usage; exit 1 # E_INVALID_OPTION; + exit 1 # E_INVALID_OPTION; fi set -- "${OPTRET[@]}" unset OPT_SHORT OPT_LONG OPTRET -- cgit v1.2.3-24-g4f1b From 00ab01e6342b7183d5a16ae57497b19dc1c2c7dc Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Sun, 8 Apr 2012 15:12:27 -0400 Subject: scripts/library: remove parse_options This is retired, as the two consumers of this function are now using the new parseopts instead. Signed-off-by: Dave Reisner --- scripts/Makefile.am | 3 +- scripts/library/README | 6 --- scripts/library/parse_options.sh | 105 --------------------------------------- scripts/po/POTFILES.in | 1 - 4 files changed, 1 insertion(+), 114 deletions(-) delete mode 100644 scripts/library/parse_options.sh (limited to 'scripts') diff --git a/scripts/Makefile.am b/scripts/Makefile.am index fc70732f..b8a19900 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -27,8 +27,7 @@ EXTRA_DIST = \ LIBRARY = \ library/output_format.sh \ - library/parseopts.sh \ - library/parse_options.sh + library/parseopts.sh # Files that should be removed, but which Automake does not know. MOSTLYCLEANFILES = $(bin_SCRIPTS) diff --git a/scripts/library/README b/scripts/library/README index f43873f3..c71c0714 100644 --- a/scripts/library/README +++ b/scripts/library/README @@ -8,12 +8,6 @@ and can be silenced by defining 'QUIET'. The 'warning' and 'error' functions print to stderr with the appropriate prefix added to the message. -parse_options.sh: -A getopt replacement to avoids portability issues, in particular the -lack of long option name support in the default getopt provided by some -platforms. -Usage: parse_option $SHORT_OPTS $LONG_OPTS "$@" - parseopts.sh: A getopt_long-like parser which portably supports longopts and shortopts with some GNU extensions. It does not allow for options with optional diff --git a/scripts/library/parse_options.sh b/scripts/library/parse_options.sh deleted file mode 100644 index 039eef92..00000000 --- a/scripts/library/parse_options.sh +++ /dev/null @@ -1,105 +0,0 @@ -# getopt like parser -parse_options() { - local short_options=$1; shift; - local long_options=$1; shift; - local ret=0; - local unused_options="" - local i - - while [[ -n $1 ]]; do - if [[ ${1:0:2} = '--' ]]; then - if [[ -n ${1:2} ]]; then - local match="" - for i in ${long_options//,/ }; do - if [[ ${1:2} = ${i//:} ]]; then - match=$i - break - fi - done - if [[ -n $match ]]; then - local needsargument=0 - - [[ ${match} = ${1:2}: ]] && needsargument=1 - [[ ${match} = ${1:2}:: && -n $2 && ${2:0:1} != "-" ]] && needsargument=1 - - if (( ! needsargument )); then - printf ' %s' "$1" - else - if [[ -n $2 ]]; then - printf ' %s ' "$1" - shift - printf "'%q" "$1" - while [[ -n $2 && ${2:0:1} != "-" ]]; do - shift - printf " %q" "$1" - done - printf "'" - else - printf "@SCRIPTNAME@: $(gettext "option %s requires an argument\n")" "'$1'" >&2 - ret=1 - fi - fi - else - echo "@SCRIPTNAME@: $(gettext "unrecognized option") '$1'" >&2 - ret=1 - fi - else - shift - break - fi - elif [[ ${1:0:1} = '-' ]]; then - for ((i=1; i<${#1}; i++)); do - if [[ $short_options =~ ${1:i:1} ]]; then - local needsargument=0 - - [[ $short_options =~ ${1:i:1}: && ! $short_options =~ ${1:i:1}:: ]] && needsargument=1 - [[ $short_options =~ ${1:i:1}:: && \ - ( -n ${1:$i+1} || ( -n $2 && ${2:0:1} != "-" ) ) ]] && needsargument=1 - - if (( ! needsargument )); then - printf ' -%s' "${1:i:1}" - else - if [[ -n ${1:$i+1} ]]; then - printf ' -%s ' "${1:i:1}" - printf "'%q" "${1:$i+1}" - while [[ -n $2 && ${2:0:1} != "-" ]]; do - shift - printf " %q" "$1" - done - printf "'" - else - if [[ -n $2 ]]; then - printf ' -%s ' "${1:i:1}" - shift - printf "'%q" "$1" - while [[ -n $2 && ${2:0:1} != "-" ]]; do - shift - printf " %q" "$1" - done - printf "'" - - else - printf "@SCRIPTNAME@: $(gettext "option %s requires an argument\n")" "'-${1:i:1}'" >&2 - ret=1 - fi - fi - break - fi - else - echo "@SCRIPTNAME@: $(gettext "unrecognized option") '-${1:i:1}'" >&2 - ret=1 - fi - done - else - unused_options="${unused_options} '$1'" - fi - shift - done - - printf " --" - [[ $unused_options ]] && printf ' %s' "${unused_options[@]}" - [[ $1 ]] && printf " '%s'" "$@" - printf "\n" - - return $ret -} diff --git a/scripts/po/POTFILES.in b/scripts/po/POTFILES.in index 01cc235f..162731b9 100644 --- a/scripts/po/POTFILES.in +++ b/scripts/po/POTFILES.in @@ -8,5 +8,4 @@ scripts/pacman-optimize.sh.in scripts/pkgdelta.sh.in scripts/repo-add.sh.in scripts/library/output_format.sh -scripts/library/parse_options.sh scripts/library/parseopts.sh -- cgit v1.2.3-24-g4f1b From 2d0a00b409cc76527d71d01acd1d517db11a0ff0 Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Sun, 8 Apr 2012 15:40:18 -0400 Subject: pacman-key: allow verification of multiple sig files Loop through arguments passed to verify_sig and treat each as a signature to be verified against a source file. Output each file as its checked to avoid ambiguity. Signed-off-by: Dave Reisner --- scripts/pacman-key.sh.in | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'scripts') diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index 75564930..bd2c7397 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -66,7 +66,7 @@ usage() { printf -- "$(gettext " -l, --list-keys List the specified or all keys")\n" printf -- "$(gettext " -r, --recv-keys Fetch the specified keyids")\n" printf -- "$(gettext " -u, --updatedb Update the trustdb of pacman")\n" - printf -- "$(gettext " -v, --verify Verify the file specified by the signature")\n" + printf -- "$(gettext " -v, --verify Verify the file(s) specified by the signature(s)")\n" printf -- "$(gettext " --edit-key Present a menu for key management task on keyids")\n" printf -- "$(gettext " --import Imports pubring.gpg from dir(s)")\n" printf -- "$(gettext " --import-trustdb Imports ownertrust values from trustdb.gpg in dir(s)")\n" @@ -439,10 +439,15 @@ refresh_keys() { } verify_sig() { - if ! "${GPG_PACMAN[@]}" --status-fd 1 --verify "$1" | grep -qE 'TRUST_(FULLY|ULTIMATE)'; then - error "$(gettext "The signature identified by %s could not be verified.")" "$1" - exit 1 - fi + local ret=0 + for sig; do + msg "Checking %s ..." "$sig" + if ! "${GPG_PACMAN[@]}" --status-fd 1 --verify "$sig" | grep -qE 'TRUST_(FULLY|ULTIMATE)'; then + error "$(gettext "The signature identified by %s could not be verified.")" "$sig" + ret=1 + fi + done + exit $ret } updatedb() { -- cgit v1.2.3-24-g4f1b