From 61c6ae01b3315c5db38ef5d313ac6f0b75fe2209 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 10 Oct 2011 21:26:17 -0500 Subject: VerbosePkgLists: format table lines in i18n-compatible way MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This had the unfortunate implementation detail that depended on the strings having 1 byte == 1 column hold true. As we know, this is not at all the case once you move past the base ASCII character set. Reimplement this whole thing so it doesn't depend on format strings at all. Instead, simply calculate the max column widths, and then when displaying each row add the correct amount of padding using UTF-8 safe string length functions. Before: 名字 旧版本新版本 净变化 下载大小 libgee 0.6.2.1-1 0.60 MiB 0.10 MiB libsocialweb 0.25.19-2 1.92 MiB 0.23 MiB folks 0.6.3.2-1 1.38 MiB 0.25 MiB After: 名字 旧版本 新版本 净变化 下载大小 libgee 0.6.2.1-1 0.60 MiB 0.10 MiB libsocialweb 0.25.19-2 1.92 MiB 0.23 MiB folks 0.6.3.2-1 1.38 MiB 0.25 MiB Signed-off-by: Dan McGee --- NEWS | 1 + src/pacman/util.c | 91 +++++++++++++++++++++++++++++-------------------------- 2 files changed, 49 insertions(+), 43 deletions(-) diff --git a/NEWS b/NEWS index 14ba65de..b4d3226c 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,6 @@ VERSION DESCRIPTION ----------------------------------------------------------------------------- +4.0.1 - Ensure VerbosePkgList table display supports multibyte chars 4.0.0 - well-integrated and powerful signed packages and databases support in pacman, the library, and scripts (FS#5331) - over 800 commits to pacman.git since 3.5.4 release diff --git a/src/pacman/util.c b/src/pacman/util.c index 79fb54dc..ee8fe3ff 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -488,34 +488,47 @@ void string_display(const char *title, const char *string) } static void table_print_line(const alpm_list_t *line, - const alpm_list_t *formats) + size_t colcount, size_t *widths) { - const alpm_list_t *curformat = formats; - const alpm_list_t *curcell = line; - - while(curcell && curformat) { - printf(alpm_list_getdata(curformat), alpm_list_getdata(curcell)); - curcell = alpm_list_next(curcell); - curformat = alpm_list_next(curformat); + size_t i; + const alpm_list_t *curcell; + + for(i = 0, curcell = line; curcell && i < colcount; + i++, curcell = alpm_list_next(curcell)) { + const char *value = curcell->data; + size_t len = string_length(value); + /* silly printf requires padding size to be an int */ + int padding = (int)widths[i] - (int)len; + if(padding < 0) { + padding = 0; + } + /* left-align all but the last column */ + if(i + 1 < colcount) { + printf("%s%*s", value, padding, ""); + } else { + printf("%*s%s", padding, "", value); + } } printf("\n"); } -/* creates format strings by checking max cell lengths in cols */ -static alpm_list_t *table_create_format(const alpm_list_t *header, - const alpm_list_t *rows) +/* find the max string width of each column */ +static size_t table_calc_widths(const alpm_list_t *header, + const alpm_list_t *rows, size_t totalcols, size_t **widths) { - alpm_list_t *formats = NULL; const alpm_list_t *i; const unsigned short padding = 2; - size_t curcol, totalcols, totalwidth = 0; + size_t curcol, totalwidth = 0; size_t *colwidths; - totalcols = alpm_list_count(header); + if(totalcols <= 0) { + return 0; + } + colwidths = malloc(totalcols * sizeof(size_t)); if(!colwidths) { - return NULL; + return 0; } /* header determines column count and initial values of longest_strs */ for(i = header, curcol = 0; i; i = alpm_list_next(i), curcol++) { @@ -536,30 +549,16 @@ static alpm_list_t *table_create_format(const alpm_list_t *header, } } - /* now use the column width info to generate format strings */ - for(curcol = 0; curcol < totalcols; curcol++) { - const char *display; - char *formatstr; - size_t colwidth = colwidths[curcol] + padding; - totalwidth += colwidth; - - /* right align the last column for a cleaner table display */ - display = (curcol + 1 < totalcols) ? "%%-%ds" : "%%%ds"; - pm_asprintf(&formatstr, display, colwidth); - - formats = alpm_list_add(formats, formatstr); - } - - free(colwidths); - - /* return NULL if terminal is not wide enough */ - if(totalwidth > getcols()) { - fprintf(stderr, _("insufficient columns available for table display\n")); - FREELIST(formats); - return NULL; + for(i = header, curcol = 0; i; i = alpm_list_next(i), curcol++) { + /* pad everything but the last column */ + if(curcol + 1 < totalcols) { + colwidths[curcol] += padding; + } + totalwidth += colwidths[curcol]; } - return formats; + *widths = colwidths; + return totalwidth; } /** Displays the list in table format @@ -576,14 +575,20 @@ int table_display(const char *title, const alpm_list_t *header, const alpm_list_t *rows) { const alpm_list_t *i; - alpm_list_t *formats; + size_t *widths = NULL, totalcols, totalwidth; if(rows == NULL || header == NULL) { return 0; } - formats = table_create_format(header, rows); - if(formats == NULL) { + totalcols = alpm_list_count(header); + totalwidth = table_calc_widths(header, rows, totalcols, &widths); + /* return -1 if terminal is not wide enough */ + if(totalwidth > getcols()) { + fprintf(stderr, _("insufficient columns available for table display\n")); + return -1; + } + if(!totalwidth || !widths) { return -1; } @@ -591,14 +596,14 @@ int table_display(const char *title, const alpm_list_t *header, printf("%s\n\n", title); } - table_print_line(header, formats); + table_print_line(header, totalcols, widths); printf("\n"); for(i = rows; i; i = alpm_list_next(i)) { - table_print_line(alpm_list_getdata(i), formats); + table_print_line(alpm_list_getdata(i), totalcols, widths); } - FREELIST(formats); + free(widths); return 0; } -- cgit v1.2.3-24-g4f1b From 2a18171afa9ba8acf1123355f252b1189aefeeeb Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 3 Oct 2011 10:52:16 -0500 Subject: signing: delay gpgme_init() until latest possible moment In the default configuration, we can enter the signing code but still have nothing to do with GPGME- for example, if database signatures are optional but none are present. Delay initialization of GPGME until we know there is a signature file present or we were passed base64-encoded data. This also makes debugging with valgrind a lot easier as you don't have to deal with all the GPGME error noise because their code leaks like a sieve. Signed-off-by: Dan McGee --- lib/libalpm/signing.c | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/lib/libalpm/signing.c b/lib/libalpm/signing.c index c30cda09..4042efbd 100644 --- a/lib/libalpm/signing.c +++ b/lib/libalpm/signing.c @@ -370,7 +370,7 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, const char *base64_sig, alpm_siglist_t *siglist) { int ret = -1, sigcount; - gpgme_error_t err; + gpgme_error_t err = 0; gpgme_ctx_t ctx; gpgme_data_t filedata, sigdata; gpgme_verify_result_t verify_result; @@ -394,9 +394,27 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, _alpm_access(handle, NULL, sigpath, R_OK); } + /* does the file we are verifying exist? */ + file = fopen(path, "rb"); + if(file == NULL) { + handle->pm_errno = ALPM_ERR_NOT_A_FILE; + goto error; + } + + /* does the sig file exist (if we didn't get the data directly)? */ + if(!base64_sig) { + sigfile = fopen(sigpath, "rb"); + if(sigfile == NULL) { + _alpm_log(handle, ALPM_LOG_DEBUG, "sig path %s could not be opened\n", + sigpath); + handle->pm_errno = ALPM_ERR_SIG_MISSING; + goto error; + } + } + if(init_gpgme(handle)) { /* pm_errno was set in gpgme_init() */ - return -1; + goto error; } _alpm_log(handle, ALPM_LOG_DEBUG, "checking signature for %s\n", path); @@ -409,11 +427,6 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, CHECK_ERR(); /* create our necessary data objects to verify the signature */ - file = fopen(path, "rb"); - if(file == NULL) { - handle->pm_errno = ALPM_ERR_NOT_A_FILE; - goto error; - } err = gpgme_data_new_from_stream(&filedata, file); CHECK_ERR(); @@ -425,19 +438,12 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, &decoded_sigdata, &data_len); if(decode_ret) { handle->pm_errno = ALPM_ERR_SIG_INVALID; - goto error; + goto gpg_error; } err = gpgme_data_new_from_mem(&sigdata, (char *)decoded_sigdata, data_len, 0); } else { /* file-based, it is on disk */ - sigfile = fopen(sigpath, "rb"); - if(sigfile == NULL) { - _alpm_log(handle, ALPM_LOG_DEBUG, "sig path %s could not be opened\n", - sigpath); - handle->pm_errno = ALPM_ERR_SIG_MISSING; - goto error; - } err = gpgme_data_new_from_stream(&sigdata, sigfile); } CHECK_ERR(); @@ -450,14 +456,14 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, if(!verify_result || !verify_result->signatures) { _alpm_log(handle, ALPM_LOG_DEBUG, "no signatures returned\n"); handle->pm_errno = ALPM_ERR_SIG_MISSING; - goto error; + goto gpg_error; } for(gpgsig = verify_result->signatures, sigcount = 0; gpgsig; gpgsig = gpgsig->next, sigcount++); _alpm_log(handle, ALPM_LOG_DEBUG, "%d signatures returned\n", sigcount); CALLOC(siglist->results, sigcount, sizeof(alpm_sigresult_t), - handle->pm_errno = ALPM_ERR_MEMORY; goto error); + handle->pm_errno = ALPM_ERR_MEMORY; goto gpg_error); siglist->count = sigcount; for(gpgsig = verify_result->signatures, sigcount = 0; gpgsig; @@ -488,7 +494,7 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, err = GPG_ERR_NO_ERROR; /* we dupe the fpr in this case since we have no key to point at */ STRDUP(result->key.fingerprint, gpgsig->fpr, - handle->pm_errno = ALPM_ERR_MEMORY; goto error); + handle->pm_errno = ALPM_ERR_MEMORY; goto gpg_error); } else { CHECK_ERR(); if(key->uids) { @@ -555,10 +561,12 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, ret = 0; -error: +gpg_error: gpgme_data_release(sigdata); gpgme_data_release(filedata); gpgme_release(ctx); + +error: if(sigfile) { fclose(sigfile); } -- cgit v1.2.3-24-g4f1b From 12642a299b9f4218f43ce8a4f1d9924cfae744ee Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Wed, 12 Oct 2011 17:32:54 -0500 Subject: Add user-visible warning message if public keyring not found This should help point users in the right direction if they have not initialized via pacman-key just yet. Signed-off-by: Dan McGee --- lib/libalpm/signing.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/libalpm/signing.c b/lib/libalpm/signing.c index 4042efbd..bdaa83ad 100644 --- a/lib/libalpm/signing.c +++ b/lib/libalpm/signing.c @@ -140,6 +140,9 @@ static int init_gpgme(alpm_handle_t *handle) || _alpm_access(handle, sigdir, "trustdb.gpg", R_OK)) { handle->pm_errno = ALPM_ERR_NOT_A_FILE; _alpm_log(handle, ALPM_LOG_DEBUG, "Signature verification will fail!\n"); + _alpm_log(handle, ALPM_LOG_WARNING, + _("Public keyring not found; have you run '%s'?\n"), + "pacman-key --init"); } /* calling gpgme_check_version() returns the current version and runs -- cgit v1.2.3-24-g4f1b From d4c97ea2f64cafd3e14e2817d2b805f0b0d541f1 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 13 Oct 2011 17:23:19 +0200 Subject: repo-add: Avoid race condition in signal handlers There is a small chance that a user sends SIGINT (or any other signal that is trapped) when we're already in clean_up() which used to lead to trap_exit() being executed and the remaining code in clean_up() being skipped due to the bash signal/trap handler blocking EXIT (since its handler is already being executed, even if it's interrupted). In practice, this behaviour caused unexpected results (primarily because pressing ^C at the wrong time left a lock file behind): $ ./repo-add extra.db.tar.gz foobar ==> Extracting database to a temporary location... ^C ==> ERROR: Aborted by user! Exiting... $ ./repo-add extra.db.tar.gz foobar ==> Extracting database to a temporary location... ==> ERROR: File 'foobar' not found. ==> No packages modified, nothing to do. ^C ==> ERROR: Aborted by user! Exiting... $ ./repo-add extra.db.tar.gz foobar ==> ERROR: Failed to acquire lockfile: extra.db.tar.gz.lck. ==> ERROR: Held by process 18522 Fix this and reduce the chance of race conditions in signal handlers by: * Unhooking all traps in both clean_up() and trap_exit(). * Call clean_up() explicitly in trap_exit() to make sure we remove the lock file and the temporary directory even if we send SIGINT when clean_up() is already being executed but didn't reach the unhook code yet. Also, add an optional parameter to clean_up() to allow for setting an explicit exit code when we call clean_up() from trap_exit(). Signed-off-by: Lukas Fleischer Signed-off-by: Dan McGee --- scripts/repo-add.sh.in | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/repo-add.sh.in b/scripts/repo-add.sh.in index 29b150c8..d147b875 100644 --- a/scripts/repo-add.sh.in +++ b/scripts/repo-add.sh.in @@ -520,13 +520,19 @@ remove() { } trap_exit() { + # unhook all traps to avoid race conditions + trap '' EXIT TERM HUP QUIT INT ERR + echo error "$@" - exit 1 + clean_up 1 } clean_up() { - local exit_code=$? + local exit_code=${1:-$?} + + # unhook all traps to avoid race conditions + trap '' EXIT TERM HUP QUIT INT ERR [[ -d $tmpdir ]] && rm -rf "$tmpdir" (( CLEAN_LOCK )) && [[ -f $LOCKFILE ]] && rm -f "$LOCKFILE" -- cgit v1.2.3-24-g4f1b From 241946cceaf4c90624794a17c6a13661ea9862a9 Mon Sep 17 00:00:00 2001 From: Lukas Fleischer Date: Thu, 13 Oct 2011 17:23:20 +0200 Subject: scripts/*.sh.in: Fix signal handler error messages This includes some fixes to the messages that are displayed when a signal is caught in makepkg or repo-add: * Instead of always showing "==> ERROR: TERM signal caught. Exiting...", replace "TERM" by whatever signal is actually caught. * Fix a typo in the SIGERR error message in repo-add ("occurred" instead of "occured"). Francois already fixed this for makepkg in 1e51b81c. Signed-off-by: Lukas Fleischer Signed-off-by: Dan McGee --- scripts/makepkg.sh.in | 4 +++- scripts/repo-add.sh.in | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index 50cf2725..09c1e963 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -179,7 +179,9 @@ clean_up() { ## set -E trap 'clean_up' 0 -trap 'trap_exit "$(gettext "TERM signal caught. Exiting...")"' TERM HUP QUIT +for signal in TERM HUP QUIT; do + trap "trap_exit \"$(gettext "%s signal caught. Exiting...")\" \"$signal\"" "$signal" +done trap 'trap_exit "$(gettext "Aborted by user! Exiting...")"' INT trap 'trap_exit "$(gettext "An unknown error has occurred. Exiting...")"' ERR diff --git a/scripts/repo-add.sh.in b/scripts/repo-add.sh.in index d147b875..5e1d7702 100644 --- a/scripts/repo-add.sh.in +++ b/scripts/repo-add.sh.in @@ -572,9 +572,11 @@ tmpdir=$(mktemp -d /tmp/repo-tools.XXXXXXXXXX) || (\ mkdir $tmpdir/tree trap 'clean_up' EXIT -trap 'trap_exit "$(gettext "TERM signal caught. Exiting...")"' TERM HUP QUIT +for signal in TERM HUP QUIT; do + trap "trap_exit \"$(gettext "%s signal caught. Exiting...")\" \"$signal\"" "$signal" +done trap 'trap_exit "$(gettext "Aborted by user! Exiting...")"' INT -trap 'trap_exit "$(gettext "An unknown error has occured. Exiting...")"' ERR +trap 'trap_exit "$(gettext "An unknown error has occurred. Exiting...")"' ERR declare -a args success=0 -- cgit v1.2.3-24-g4f1b From 04fd320e97770911894fb06ba98f3c17fc30c7d9 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 13 Oct 2011 11:22:50 -0500 Subject: Update NEWS for missing 4.0 stuff and 4.0.1 changes so far Signed-off-by: Dan McGee --- NEWS | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index b4d3226c..25919bc7 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ VERSION DESCRIPTION ----------------------------------------------------------------------------- -4.0.1 - Ensure VerbosePkgList table display supports multibyte chars +4.0.1 - ensure VerbosePkgList table display supports multibyte chars + - add guidance message for users when public keyring not found + - repo-add: fix race condition around lock file removal 4.0.0 - well-integrated and powerful signed packages and databases support in pacman, the library, and scripts (FS#5331) - over 800 commits to pacman.git since 3.5.4 release @@ -45,6 +47,7 @@ VERSION DESCRIPTION - makepkg: - allow signing packages after creation - allow verifying source file signatures (FS#20448) + - add auto-versioned libdepends/libprovides support - support UPX compression of executables (FS#17213) - allow usage of an alternate build directory (FS#22308) - cleancache option has been removed; use shell instead -- cgit v1.2.3-24-g4f1b