diff --git a/configure.ac b/configure.ac index 6941054f..45e0111a 100644 --- a/configure.ac +++ b/configure.ac @@ -174,7 +174,9 @@ AM_CONDITIONAL([HAVE_LIBGPGME], [test "x$with_gpgme" = "xyes"]) # Checks for header files. AC_CHECK_HEADERS([fcntl.h float.h glob.h libintl.h limits.h locale.h \ - mntent.h stddef.h string.h sys/ioctl.h sys/mount.h \ + mntent.h netinet/in.h netinet/tcp.h \ + stddef.h string.h sys/ioctl.h \ + sys/mnttab.h sys/mount.h \ sys/param.h sys/statvfs.h sys/time.h sys/types.h \ sys/ucred.h syslog.h termios.h wchar.h]) diff --git a/contrib/bash_completion.in b/contrib/bash_completion.in index d9f8d826..529734c3 100644 --- a/contrib/bash_completion.in +++ b/contrib/bash_completion.in @@ -59,9 +59,9 @@ _makepkg() { _pacman_pkg() { _arch_compgen "$( if [[ $2 ]]; then - \pacman -$1 | \cut -d' ' -f1 | \sort -u + \pacman -$1 2>/dev/null | \cut -d' ' -f1 | \sort -u else - \pacman -$1 + \pacman -$1 2>/dev/null fi )" } diff --git a/contrib/zsh_completion.in b/contrib/zsh_completion.in index f3130867..b30e9600 100644 --- a/contrib/zsh_completion.in +++ b/contrib/zsh_completion.in @@ -276,7 +276,7 @@ _pacman_completions_repositories() { # $cmd must be declared by calling function _pacman_get_command() { # this is mostly nicked from _perforce - cmd=( "pacman" ) + cmd=( "pacman" "2>/dev/null") integer i for (( i = 2; i < CURRENT - 1; i++ )); do if [[ ${words[i]} = "--config" || ${words[i]} = "--root" ]]; then diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt index 39551e15..0813b887 100644 --- a/doc/pacman.8.txt +++ b/doc/pacman.8.txt @@ -349,7 +349,7 @@ Sync Options[[SO]] databases are saved for every sync DB you download from, and are not deleted even if they are removed from the configuration file linkman:pacman.conf[5]. Use one '\--clean' switch to only remove - packages that are no longer installed; use two to remove all packages + packages that are no longer installed; use two to remove all files from the cache. In both cases, you will have a yes or no option to remove packages and/or unused downloaded databases. + diff --git a/doc/vercmp.8.txt b/doc/vercmp.8.txt index 4b0490fa..6b94f3e4 100644 --- a/doc/vercmp.8.txt +++ b/doc/vercmp.8.txt @@ -6,7 +6,7 @@ vercmp(8) Name ---- -vercmp - version comparsion utility +vercmp - version comparison utility Synopsis @@ -23,7 +23,7 @@ numbers. It outputs values as follows: * = 0 : if ver1 == ver2 * > 0 : if ver1 > ver2 -Version comparsion operates as follows: +Version comparison operates as follows: Alphanumeric: 1.0a < 1.0b < 1.0beta < 1.0p < 1.0pre < 1.0rc < 1.0 < 1.0.a < 1.0.1 @@ -35,6 +35,11 @@ overrule any version comparison (unless the epoch values are equal). This is specified in an `epoch:version-rel` format. For example, `2:1.0-1` is always greater than `1:3.6-1`. +Keep in mind that the 'pkgrel' is only compared if it is available on both +versions given to this tool. For example, comparing `1.5-1` and `1.5` will +yield 0; comparing `1.5-1` and `1.5-2` will yield < 0 as expected. This is +mainly for supporting versioned dependencies that do not include the 'pkgrel'. + Options ------- diff --git a/lib/libalpm/diskspace.c b/lib/libalpm/diskspace.c index 274aa676..91b655e5 100644 --- a/lib/libalpm/diskspace.c +++ b/lib/libalpm/diskspace.c @@ -1,7 +1,7 @@ /* * diskspace.c * - * Copyright (c) 2010-2011 Pacman Development Team + * Copyright (c) 2010-2012 Pacman Development Team * * 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 @@ -17,10 +17,17 @@ * along with this program. If not, see . */ +#include "config.h" + +#include #include + #if defined(HAVE_MNTENT_H) #include #endif +#if defined(HAVE_SYS_MNTTAB_H) +#include +#endif #if defined(HAVE_SYS_STATVFS_H) #include #endif @@ -69,10 +76,10 @@ static alpm_list_t *mount_point_list(alpm_handle_t *handle) alpm_list_t *mount_points = NULL, *ptr; alpm_mountpoint_t *mp; -#if defined HAVE_GETMNTENT +#if defined(HAVE_GETMNTENT) && defined(HAVE_MNTENT_H) + /* Linux */ struct mntent *mnt; FILE *fp; - struct statvfs fsp; fp = setmntent(MOUNTED, "r"); @@ -81,8 +88,10 @@ static alpm_list_t *mount_point_list(alpm_handle_t *handle) } while((mnt = getmntent(fp))) { + struct statvfs fsp; if(!mnt) { - _alpm_log(handle, ALPM_LOG_WARNING, _("could not get filesystem information\n")); + _alpm_log(handle, ALPM_LOG_WARNING, + _("could not get filesystem information\n")); continue; } if(statvfs(mnt->mnt_dir, &fsp) != 0) { @@ -102,7 +111,44 @@ static alpm_list_t *mount_point_list(alpm_handle_t *handle) } endmntent(fp); -#elif defined HAVE_GETMNTINFO +#elif defined(HAVE_GETMNTENT) && defined(HAVE_MNTTAB_H) + /* Solaris, Illumos */ + struct mnttab mnt; + FILE *fp; + int ret; + + fp = fopen("/etc/mnttab", "r"); + + if(fp == NULL) { + return NULL; + } + + while((ret = getmntent(fp, &mnt)) == 0) { + struct statvfs fsp; + if(statvfs(mnt->mnt_mountp, &fsp) != 0) { + _alpm_log(handle, ALPM_LOG_WARNING, + _("could not get filesystem information for %s: %s\n"), + mnt->mnt_mountp, strerror(errno)); + continue; + } + + CALLOC(mp, 1, sizeof(alpm_mountpoint_t), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); + mp->mount_dir = strdup(mnt->mnt_mountp); + mp->mount_dir_len = strlen(mp->mount_dir); + memcpy(&(mp->fsp), &fsp, sizeof(struct statvfs)); + mp->read_only = fsp.f_flag & ST_RDONLY; + + mount_points = alpm_list_add(mount_points, mp); + } + /* -1 == EOF */ + if(ret != -1) { + _alpm_log(handle, ALPM_LOG_WARNING, + _("could not get filesystem information\n")); + } + + fclose(fp); +#elif defined(HAVE_GETMNTINFO) + /* FreeBSD (statfs), NetBSD (statvfs), OpenBSD (statfs), OS X (statfs) */ int entries; FSSTATSTYPE *fsp; diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index a3980d65..97778c27 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -1,7 +1,7 @@ /* * download.c * - * Copyright (c) 2006-2011 Pacman Development Team + * Copyright (c) 2006-2012 Pacman Development Team * Copyright (c) 2002-2006 by Judd Vinet * * This program is free software; you can redistribute it and/or modify @@ -23,11 +23,19 @@ #include #include #include +#include /* setsockopt, SO_KEEPALIVE */ #include #include #include #include +#ifdef HAVE_NETINET_IN_H +#include /* IPPROTO_TCP */ +#endif +#ifdef HAVE_NETINET_TCP_H +#include /* TCP_KEEPINTVL, TCP_KEEPIDLE */ +#endif + #ifdef HAVE_LIBCURL #include #endif @@ -82,7 +90,7 @@ static void inthandler(int UNUSED signum) dload_interrupted = ABORT_SIGINT; } -static int curl_progress(void *file, double dltotal, double dlnow, +static int dload_progress_cb(void *file, double dltotal, double dlnow, double UNUSED ultotal, double UNUSED ulnow) { struct dload_payload *payload = (struct dload_payload *)file; @@ -184,7 +192,7 @@ static mode_t _getumask(void) return mask; } -static size_t parse_headers(void *ptr, size_t size, size_t nmemb, void *user) +static size_t dload_parseheader_cb(void *ptr, size_t size, size_t nmemb, void *user) { size_t realsize = size * nmemb; const char *fptr, *endptr = NULL; @@ -215,6 +223,47 @@ static size_t parse_headers(void *ptr, size_t size, size_t nmemb, void *user) return realsize; } +static int dload_sockopt_cb(void *userdata, curl_socket_t curlfd, + curlsocktype purpose) +{ + alpm_handle_t *handle = userdata; + int optval = 1; + + /* this whole method is to prevent FTP control connections from going sour + * during a long data transfer; crappy firewalls love to drop otherwise idle + * connections if there is no traffic. */ + if(purpose != CURLSOCKTYPE_IPCXN) { + return 0; + } + + /* don't abort operation if any setsockopt fails, just log to debug */ + if(setsockopt(curlfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&optval, + sizeof(optval)) < 0) { + _alpm_log(handle, ALPM_LOG_DEBUG, + "Failed to set SO_KEEPALIVE on fd %d\n", curlfd); + } + else { +#ifdef TCP_KEEPIDLE + optval = 60; + if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&optval, + sizeof(optval)) < 0) { + _alpm_log(handle, ALPM_LOG_DEBUG, + "Failed to set TCP_KEEPIDLE on fd %d\n", curlfd); + } +#endif +#ifdef TCP_KEEPINTVL + optval = 60; + if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&optval, + sizeof(optval)) < 0) { + _alpm_log(handle, ALPM_LOG_DEBUG, + "Failed to set TCP_KEEPINTVL on fd %d\n", curlfd); + } +#endif + } + + return 0; +} + static void curl_set_handle_opts(struct dload_payload *payload, CURL *curl, char *error_buffer) { @@ -232,13 +281,15 @@ static void curl_set_handle_opts(struct dload_payload *payload, curl_easy_setopt(curl, CURLOPT_FILETIME, 1L); curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, curl_progress); + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, dload_progress_cb); curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, (void *)payload); curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1024L); curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 10L); - curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, parse_headers); + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, dload_parseheader_cb); curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *)payload); curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); + curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, dload_sockopt_cb); + curl_easy_setopt(curl, CURLOPT_SOCKOPTDATA, (void *)handle); _alpm_log(handle, ALPM_LOG_DEBUG, "url: %s\n", payload->fileurl); @@ -388,6 +439,8 @@ static int curl_download_internal(struct dload_payload *payload, /* perform transfer */ payload->curlerr = curl_easy_perform(curl); + _alpm_log(handle, ALPM_LOG_DEBUG, "curl returned error %d from transfer\n", + payload->curlerr); /* disconnect relationships from the curl handle for things that might go out * of scope, but could still be touched on connection teardown. This really @@ -558,6 +611,22 @@ int _alpm_download(struct dload_payload *payload, const char *localpath, } } +static char *filecache_find_url(alpm_handle_t *handle, const char *url) +{ + const char *basename = strrchr(url, '/'); + + if(basename == NULL) { + return NULL; + } + + basename++; + if(basename == '\0') { + return NULL; + } + + return _alpm_filecache_find(handle, basename); +} + /** Fetch a remote pkg. */ char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) { @@ -565,7 +634,7 @@ char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) const char *cachedir; char *final_file = NULL; struct dload_payload payload; - int ret; + int ret = 0; CHECK_HANDLE(handle, return NULL); ASSERT(url, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL)); @@ -574,51 +643,63 @@ char SYMEXPORT *alpm_fetch_pkgurl(alpm_handle_t *handle, const char *url) cachedir = _alpm_filecache_setup(handle); memset(&payload, 0, sizeof(struct dload_payload)); - payload.handle = handle; - STRDUP(payload.fileurl, url, RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); - payload.allow_resume = 1; - /* download the file */ - ret = _alpm_download(&payload, cachedir, &final_file); - _alpm_dload_payload_reset(&payload); - if(ret == -1) { - _alpm_log(handle, ALPM_LOG_WARNING, _("failed to download %s\n"), url); - free(final_file); - return NULL; + /* attempt to find the file in our pkgcache */ + filepath = filecache_find_url(handle, url); + if(filepath == NULL) { + STRDUP(payload.fileurl, url, RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); + payload.allow_resume = 1; + payload.handle = handle; + + /* download the file */ + ret = _alpm_download(&payload, cachedir, &final_file); + _alpm_dload_payload_reset(&payload); + if(ret == -1) { + _alpm_log(handle, ALPM_LOG_WARNING, _("failed to download %s\n"), url); + free(final_file); + return NULL; + } + _alpm_log(handle, ALPM_LOG_DEBUG, "successfully downloaded %s\n", url); } - _alpm_log(handle, ALPM_LOG_DEBUG, "successfully downloaded %s\n", url); /* attempt to download the signature */ if(ret == 0 && (handle->siglevel & ALPM_SIG_PACKAGE)) { - char *sig_final_file = NULL; + char *sig_filepath, *sig_final_file = NULL; size_t len; len = strlen(url) + 5; MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); snprintf(payload.fileurl, len, "%s.sig", url); - payload.handle = handle; - payload.force = 1; - payload.errors_ok = (handle->siglevel & ALPM_SIG_PACKAGE_OPTIONAL); - /* set hard upper limit of 16KiB */ - payload.max_size = 16 * 1024; + sig_filepath = filecache_find_url(handle, payload.fileurl); + if(sig_filepath == NULL) { + payload.handle = handle; + payload.force = 1; + payload.errors_ok = (handle->siglevel & ALPM_SIG_PACKAGE_OPTIONAL); - ret = _alpm_download(&payload, cachedir, &sig_final_file); - if(ret == -1 && !payload.errors_ok) { - _alpm_log(handle, ALPM_LOG_WARNING, - _("failed to download %s\n"), payload.fileurl); - /* Warn now, but don't return NULL. We will fail later during package - * load time. */ - } else if(ret == 0) { - _alpm_log(handle, ALPM_LOG_DEBUG, - "successfully downloaded %s\n", payload.fileurl); + /* set hard upper limit of 16KiB */ + payload.max_size = 16 * 1024; + + ret = _alpm_download(&payload, cachedir, &sig_final_file); + if(ret == -1 && !payload.errors_ok) { + _alpm_log(handle, ALPM_LOG_WARNING, + _("failed to download %s\n"), payload.fileurl); + /* Warn now, but don't return NULL. We will fail later during package + * load time. */ + } else if(ret == 0) { + _alpm_log(handle, ALPM_LOG_DEBUG, + "successfully downloaded %s\n", payload.fileurl); + } + FREE(sig_final_file); } - FREE(sig_final_file); + free(sig_filepath); _alpm_dload_payload_reset(&payload); } /* we should be able to find the file the second time around */ - filepath = _alpm_filecache_find(handle, final_file); + if(filepath == NULL) { + filepath = _alpm_filecache_find(handle, final_file); + } free(final_file); return filepath; diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index bc196510..469ce9bb 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -1,7 +1,7 @@ /* * remove.c * - * Copyright (c) 2006-2011 Pacman Development Team + * Copyright (c) 2006-2012 Pacman Development Team * Copyright (c) 2002-2006 by Judd Vinet * Copyright (c) 2005 by Aurelien Foret * Copyright (c) 2005 by Christian Hamar diff --git a/lib/libalpm/signing.c b/lib/libalpm/signing.c index 3ff83ba0..cfe0f5e8 100644 --- a/lib/libalpm/signing.c +++ b/lib/libalpm/signing.c @@ -1,7 +1,7 @@ /* * signing.c * - * Copyright (c) 2008-2011 Pacman Development Team + * Copyright (c) 2008-2012 Pacman Development Team * * 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 diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index e2cbd8c5..3cc4bbf7 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -1,7 +1,7 @@ /* * util.c * - * Copyright (c) 2006-2011 Pacman Development Team + * Copyright (c) 2006-2012 Pacman Development Team * Copyright (c) 2002-2006 by Judd Vinet * Copyright (c) 2005 by Aurelien Foret * Copyright (c) 2005 by Christian Hamar @@ -406,7 +406,6 @@ int _alpm_rmrf(const char *path) int errflag = 0; struct dirent *dp; DIR *dirp; - char name[PATH_MAX]; struct stat st; if(_alpm_lstat(path, &st) == 0) { @@ -426,9 +425,10 @@ int _alpm_rmrf(const char *path) return 1; } for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { - if(dp->d_ino) { - sprintf(name, "%s/%s", path, dp->d_name); + if(dp->d_name) { if(strcmp(dp->d_name, "..") != 0 && strcmp(dp->d_name, ".") != 0) { + char name[PATH_MAX]; + sprintf(name, "%s/%s", path, dp->d_name); errflag += _alpm_rmrf(name); } } @@ -1168,7 +1168,7 @@ off_t _alpm_strtoofft(const char *line) errno = 0; /* we are trying to parse bare numbers only, no leading anything */ - if(line[0] < '0' || line[0] > '9') { + if(!isdigit((unsigned char)line[0])) { return (off_t)-1; } result = strtoull(line, &end, 10); diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index 20440265..c761a098 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -3,7 +3,7 @@ # makepkg - make packages compatible for use with pacman # @configure_input@ # -# Copyright (c) 2006-2011 Pacman Development Team +# Copyright (c) 2006-2012 Pacman Development Team # Copyright (c) 2002-2006 by Judd Vinet # Copyright (c) 2005 by Aurelien Foret # Copyright (c) 2006 by Miklos Vajna @@ -412,7 +412,11 @@ download_file() { run_pacman() { local cmd - printf -v cmd "%q " "$PACMAN" $PACMAN_OPTS "$@" + if [[ ! $1 = -@(T|Qq) ]]; then + printf -v cmd "%q " "$PACMAN" $PACMAN_OPTS "$@" + else + printf -v cmd "%q " "$PACMAN" "$@" + fi if (( ! ASROOT )) && [[ ! $1 = -@(T|Qq) ]]; then if type -p sudo >/dev/null; then cmd="sudo $cmd" @@ -507,14 +511,15 @@ remove_deps() { # check for packages removed during dependency install (e.g. due to conflicts) # removing all installed packages is risky in this case if [[ -n $(grep -xvFf <(printf '%s\n' "${current_packagelist[@]}") \ - <(printf '%s\n' "${original_packagelist[@]}") ) ]]; then + <(printf '%s\n' "${original_packagelist[@]}") || true) ]]; then warning "$(gettext "Failed to remove installed dependencies.")" return 0 fi local deplist - if ! deplist=($(grep -xvFf <(printf "%s\n" "${original_pkglist[@]}") \ - <(printf "%s\n" "${current_pkglist[@]}"))); then + deplist=($(grep -xvFf <(printf "%s\n" "${original_pkglist[@]}") \ + <(printf "%s\n" "${current_pkglist[@]}") || true)) + if [[ -n deplist ]]; then return fi @@ -1869,7 +1874,7 @@ usage() { version() { printf "makepkg (pacman) %s\n" "$myver" printf "$(gettext "\ -Copyright (c) 2006-2011 Pacman Development Team .\n\ +Copyright (c) 2006-2012 Pacman Development Team .\n\ Copyright (C) 2002-2006 Judd Vinet .\n\n\ This is free software; see the source for copying conditions.\n\ There is NO WARRANTY, to the extent permitted by law.\n")" diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index 689dc564..4e321e63 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -4,7 +4,7 @@ # Based on apt-key, from Debian # @configure_input@ # -# Copyright (c) 2010-2011 Pacman Development Team +# Copyright (c) 2010-2012 Pacman Development Team # # 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 @@ -88,7 +88,7 @@ usage() { version() { printf "pacman-key (pacman) %s\n" "${myver}" printf "$(gettext "\ -Copyright (c) 2010-2011 Pacman Development Team .\n\ +Copyright (c) 2010-2012 Pacman Development Team .\n\ This is free software; see the source for copying conditions.\n\ There is NO WARRANTY, to the extent permitted by law.\n")" } @@ -144,6 +144,20 @@ add_gpg_conf_option() { fi } +check_keyids_exist() { + local ret=0 + for key in "${KEYIDS[@]}"; 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" + ret=1 + fi + done + if (( ret )); then + exit 1 + fi +} + initialize() { local conffile keyserv # Check for simple existence rather than for a directory as someone @@ -338,41 +352,144 @@ populate_keyring() { fi } +add_keys() { + if ! "${GPG_PACMAN[@]}" --quiet --batch --import "${KEYFILES[@]}" ; 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 + error "$(gettext "A specified key could not be removed from the gpg keychain.")" + exit 1 + fi +} + edit_keys() { - local errors=0; + check_keyids_exist + local ret=0 for key in "${KEYIDS[@]}"; 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 does not exist.")" "$key" - errors=1; + if ! "${GPG_PACMAN[@]}" --edit-key "$key" ; then + error "$(gettext "The key identified by %s could not be edited.")" "$key" + ret=1 fi done - (( errors )) && exit 1; + if (( ret )); then + exit 1 + fi +} - for key in "${KEYIDS[@]}"; do - "${GPG_PACMAN[@]}" --edit-key "$key" - done +export_keys() { + check_keyids_exist + if ! "${GPG_PACMAN[@]}" --armor --export "${KEYIDS[@]}" ; then + error "$(gettext "A specified key could not be exported from the gpg keychain.")" + exit 1 + fi +} + +finger_keys() { + check_keyids_exist + if ! "${GPG_PACMAN[@]}" --batch --fingerprint "${KEYIDS[@]}" ; then + error "$(gettext "The fingerprint of a specified key could not be determined.")" + exit 1 + fi } import_trustdb() { local importdir - + local ret=0 for importdir in "${IMPORT_DIRS[@]}"; do if [[ -f "${importdir}/trustdb.gpg" ]]; then gpg --homedir "${importdir}" --export-ownertrust | \ "${GPG_PACMAN[@]}" --import-ownertrust - + if (( PIPESTATUS )); then + error "$(gettext "%s could not be imported.")" "${importdir}/trustdb.gpg" + ret=1 + fi + else + error "$(gettext "File %s does not exist and could not be imported.")" "${importdir}/trustdb.gpg" + ret=1 fi done + if (( ret )); then + exit 1 + fi } import() { local importdir - + local ret=0 for importdir in "${IMPORT_DIRS[@]}"; do if [[ -f "${importdir}/pubring.gpg" ]]; then - "${GPG_PACMAN[@]}" --quiet --batch --import "${importdir}/pubring.gpg" + if ! "${GPG_PACMAN[@]}" --quiet --batch --import "${importdir}/pubring.gpg" ; then + error "$(gettext "%s could not be imported.")" "${importdir}/pubring.gpg" + ret=1 + fi + else + error "$(gettext "File %s does not exist and could not be imported.")" "${importdir}/pubring.gpg" + ret=1 fi done + if (( ret )); then + exit 1 + fi +} + +list_keys() { + check_keyids_exist + if ! "${GPG_PACMAN[@]}" --batch --list-keys "${KEYIDS[@]}" ; then + error "$(gettext "A specified key could not be listed.")" + exit 1 + fi +} + +list_sigs() { + check_keyids_exist + if ! "${GPG_PACMAN[@]}" --batch --list-sigs "${KEYIDS[@]}" ; then + error "$(gettext "A specified signature could not be listed.")" + exit 1 + fi +} + +lsign_keys() { + check_keyids_exist + printf 'y\ny\n' | LANG=C "${GPG_PACMAN[@]}" --command-fd 0 --quiet --batch --lsign-key "${KEYIDS[@]}" 2>/dev/null + if (( PIPESTATUS[1] )); then + error "$(gettext "A specified key could not be locally signed.")" + exit 1 + fi +} + +receive_keys() { + if ! "${GPG_PACMAN[@]}" --recv-keys "${KEYIDS[@]}" ; 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 + error "$(gettext "A specified local key could not be updated from a keyserver.")" + exit 1 + fi +} + +verify_sig() { + if ! "${GPG_PACMAN[@]}" --verify $SIGNATURE ; then + error "$(gettext "The signature identified by %s could not be verified.")" "$SIGNATURE" + exit 1 + fi +} + +updatedb() { + msg "$(gettext "Updating trust database...")" + if ! "${GPG_PACMAN[@]}" --batch --check-trustdb ; then + error "$(gettext "Trust database could not be updated.")" + exit 1 + fi } # PROGRAM START @@ -476,27 +593,24 @@ esac (( ! INIT )) && check_keyring -(( ADD )) && "${GPG_PACMAN[@]}" --quiet --batch --import "${KEYFILES[@]}" -(( DELETE )) && "${GPG_PACMAN[@]}" --quiet --batch --delete-key --yes "${KEYIDS[@]}" +(( ADD )) && add_keys +(( DELETE )) && delete_keys (( EDITKEY )) && edit_keys -(( EXPORT )) && "${GPG_PACMAN[@]}" --armor --export "${KEYIDS[@]}" -(( FINGER )) && "${GPG_PACMAN[@]}" --batch --fingerprint "${KEYIDS[@]}" +(( EXPORT )) && export_keys +(( FINGER )) && finger_keys (( IMPORT )) && import (( IMPORT_TRUSTDB)) && import_trustdb (( INIT )) && initialize -(( LISTKEYS )) && "${GPG_PACMAN[@]}" --batch --list-keys "${KEYIDS[@]}" -(( LISTSIGS )) && "${GPG_PACMAN[@]}" --batch --list-sigs "${KEYIDS[@]}" -if (( LSIGNKEY )); then - printf 'y\ny\n' | LANG=C "${GPG_PACMAN[@]}" --command-fd 0 --quiet --batch --lsign-key "${KEYIDS[@]}" 2>/dev/null -fi +(( LISTKEYS )) && list_keys +(( LISTSIGS )) && list_sigs +(( LSIGNKEY )) && lsign_keys (( POPULATE )) && populate_keyring -(( RECEIVE )) && "${GPG_PACMAN[@]}" --recv-keys "${KEYIDS[@]}" -(( REFRESH )) && "${GPG_PACMAN[@]}" --refresh-keys "${KEYIDS[@]}" -(( VERIFY )) && "${GPG_PACMAN[@]}" --verify "$SIGNATURE" +(( RECEIVE )) && receive_keys +(( REFRESH )) && refresh_keys +(( VERIFY )) && verify_sig -if (( UPDATEDB )); then - msg "$(gettext "Updating trust database...")" - "${GPG_PACMAN[@]}" --batch --check-trustdb -fi +(( UPDATEDB )) && updatedb + +exit 0 # vim: set ts=2 sw=2 noet: diff --git a/scripts/repo-add.sh.in b/scripts/repo-add.sh.in index 28339e64..48eee7ac 100644 --- a/scripts/repo-add.sh.in +++ b/scripts/repo-add.sh.in @@ -4,7 +4,7 @@ # repo-remove - remove a package entry from a given repo database file # @configure_input@ # -# Copyright (c) 2006-2011 Pacman Development Team +# Copyright (c) 2006-2012 Pacman Development Team # # 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 @@ -48,30 +48,38 @@ usage() { printf "%s (pacman) %s\n\n" "$cmd" "$myver" if [[ $cmd == "repo-add" ]] ; then printf "$(gettext "Usage: repo-add [options] ...\n")" + printf "\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")" +Multiple packages to add can be specified on the command line.\n")" + printf "\n" 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] ...\n\n")" + printf "$(gettext "Usage: repo-remove [options] ...\n")" + printf "\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")" +packages to remove can be specified on the command line.\n")" + printf "\n" printf "$(gettext "Options:\n")" + else + printf "$(gettext "Please move along, there is nothing to see here.\n")" + return fi printf "$(gettext " -q, --quiet minimize output\n")" printf "$(gettext " -s, --sign sign database with GnuPG after update\n")" printf "$(gettext " -k, --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 +See %s(8) for more details and descriptions of the available options.\n")" $cmd + printf "\n" 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")" + printf "$(gettext "Example: repo-add /path/to/repo.db.tar.gz pacman-3.0.0-1-i686.pkg.tar.gz\n")" elif [[ $cmd == "repo-remove" ]] ; then - echo "$(gettext "Example: repo-remove /path/to/repo.db.tar.gz kernel26")" + printf "$(gettext "Example: repo-remove /path/to/repo.db.tar.gz kernel26\n")" fi } @@ -79,7 +87,7 @@ version() { cmd=${0##*/} printf "%s (pacman) %s\n\n" "$cmd" "$myver" printf "$(gettext "\ -Copyright (c) 2006-2011 Pacman Development Team \n\n\ +Copyright (c) 2006-2012 Pacman Development Team \n\n\ This is free software; see the source for copying conditions.\n\ There is NO WARRANTY, to the extent permitted by law.\n")" } diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 3e17d905..014520e8 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -218,7 +218,7 @@ static void version(void) { printf("\n"); printf(" .--. Pacman v%s - libalpm v%s\n", PACKAGE_VERSION, alpm_version()); - printf("/ _.-' .-. .-. .-. Copyright (C) 2006-2011 Pacman Development Team\n"); + printf("/ _.-' .-. .-. .-. Copyright (C) 2006-2012 Pacman Development Team\n"); printf("\\ '-. '-' '-' '-' Copyright (C) 2002-2006 Judd Vinet\n"); printf(" '--'\n"); printf(_(" This program may be freely redistributed under\n" @@ -791,7 +791,7 @@ int main(int argc, char *argv[]) config = config_new(); /* disable progressbar if the output is redirected */ - if(!isatty(1)) { + if(!isatty(fileno(stdout))) { config->noprogressbar = 1; } diff --git a/src/pacman/sync.c b/src/pacman/sync.c index a13b6c7f..e22f94f7 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -1,7 +1,7 @@ /* * sync.c * - * Copyright (c) 2006-2011 Pacman Development Team + * Copyright (c) 2006-2012 Pacman Development Team * Copyright (c) 2002-2006 by Judd Vinet * * This program is free software; you can redistribute it and/or modify @@ -196,7 +196,6 @@ static int sync_cleancache(int level) /* step through the directory one file at a time */ while((ent = readdir(dir)) != NULL) { char path[PATH_MAX]; - size_t pathlen; int delete = 1; alpm_pkg_t *localpkg = NULL, *pkg = NULL; const char *local_name, *local_version; @@ -207,30 +206,18 @@ static int sync_cleancache(int level) /* build the full filepath */ snprintf(path, PATH_MAX, "%s%s", cachedir, ent->d_name); - /* short circuit for removing all packages from cache */ + /* short circuit for removing all files from cache */ if(level > 1) { unlink(path); continue; } - /* we handle .sig files with packages, not separately */ - pathlen = strlen(path); - if(strcmp(path + pathlen - 4, ".sig") == 0) { - continue; - } - - /* attempt to load the package, prompt removal on failures as we may have - * files here that aren't valid packages. we also don't need a full - * load of the package, just the metadata. */ - if(alpm_pkg_load(config->handle, path, 0, 0, &localpkg) != 0 - || localpkg == NULL) { - if(yesno(_("File %s does not seem to be a valid package, remove it?"), - path)) { - if(localpkg) { - alpm_pkg_free(localpkg); - } - unlink(path); - } + /* attempt to load the file as a package. if we cannot load the file, + * simply skip it and move on. we don't need a full load of the package, + * just the metadata. */ + if(alpm_pkg_load(config->handle, path, 0, 0, &localpkg) != 0) { + pm_printf(ALPM_LOG_DEBUG, "skipping %s, could not load as package\n", + path); continue; } local_name = alpm_pkg_get_name(localpkg); @@ -242,7 +229,7 @@ static int sync_cleancache(int level) if(pkg != NULL && alpm_pkg_vercmp(local_version, alpm_pkg_get_version(pkg)) == 0) { /* package was found in local DB and version matches, keep it */ - pm_printf(ALPM_LOG_DEBUG, "pkg %s-%s found in local db\n", + pm_printf(ALPM_LOG_DEBUG, "package %s-%s found in local db\n", local_name, local_version); delete = 0; } @@ -256,7 +243,7 @@ static int sync_cleancache(int level) if(pkg != NULL && alpm_pkg_vercmp(local_version, alpm_pkg_get_version(pkg)) == 0) { /* package was found in a sync DB and version matches, keep it */ - pm_printf(ALPM_LOG_DEBUG, "pkg %s-%s found in sync db\n", + pm_printf(ALPM_LOG_DEBUG, "package %s-%s found in sync db\n", local_name, local_version); delete = 0; } @@ -266,6 +253,7 @@ static int sync_cleancache(int level) alpm_pkg_free(localpkg); if(delete) { + size_t pathlen = strlen(path); unlink(path); /* unlink a signature file if present too */ if(PATH_MAX - 5 >= pathlen) { diff --git a/src/pacman/util.c b/src/pacman/util.c index 467bedfe..27efdb0a 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -1,7 +1,7 @@ /* * util.c * - * Copyright (c) 2006-2011 Pacman Development Team + * Copyright (c) 2006-2012 Pacman Development Team * Copyright (c) 2002-2006 by Judd Vinet * * This program is free software; you can redistribute it and/or modify @@ -190,10 +190,10 @@ int rmrf(const char *path) return 1; } for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { - if(dp->d_ino) { - char name[PATH_MAX]; - sprintf(name, "%s/%s", path, dp->d_name); + if(dp->d_name) { if(strcmp(dp->d_name, "..") != 0 && strcmp(dp->d_name, ".") != 0) { + char name[PATH_MAX]; + snprintf(name, PATH_MAX, "%s/%s", path, dp->d_name); errflag += rmrf(name); } } @@ -310,19 +310,6 @@ void indentprint(const char *str, size_t indent) free(wcstr); } -/* Convert a string to uppercase - */ -char *strtoupper(char *str) -{ - char *ptr = str; - - while(*ptr) { - (*ptr) = (char)toupper((unsigned char)*ptr); - ptr++; - } - return str; -} - /* Trim whitespace and newlines from a string */ size_t strtrim(char *str) @@ -898,8 +885,12 @@ static void _display_targets(alpm_list_t *targets, int verbose) /* add up size of all removed packages */ rsize += alpm_pkg_get_isize(target->remove); } + } + + /* form data for both verbose and non-verbose display */ + for(i = targets; i; i = alpm_list_next(i)) { + pm_target_t *target = i->data; - /* form data for both verbose and non-verbose display */ rows = alpm_list_add(rows, create_verbose_row(target, show_dl_size)); if(target->install) { pm_asprintf(&str, "%s-%s", alpm_pkg_get_name(target->install), @@ -1430,6 +1421,12 @@ static int question(short preset, char *fmt, va_list args) return preset; } + /* if stdin is piped, response does not get printed out, and as a result + * a \n is missing, resulting in broken output (FS#27909) */ + if(!isatty(fileno(stdin))) { + fprintf(stream, "%s\n", response); + } + if(strcasecmp(response, _("Y")) == 0 || strcasecmp(response, _("YES")) == 0) { return 1; } else if(strcasecmp(response, _("N")) == 0 || strcasecmp(response, _("NO")) == 0) { diff --git a/src/pacman/util.h b/src/pacman/util.h index 5d3ea2f1..18048de9 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -1,7 +1,7 @@ /* * util.h * - * Copyright (c) 2006-2011 Pacman Development Team + * Copyright (c) 2006-2012 Pacman Development Team * Copyright (c) 2002-2006 by Judd Vinet * * This program is free software; you can redistribute it and/or modify @@ -52,7 +52,6 @@ int rmrf(const char *path); const char *mbasename(const char *path); char *mdirname(const char *path); void indentprint(const char *str, size_t indent); -char *strtoupper(char *str); size_t strtrim(char *str); char *strreplace(const char *str, const char *needle, const char *replace); alpm_list_t *strsplit(const char *str, const char splitchar);