diff options
143 files changed, 4167 insertions, 4104 deletions
diff --git a/PKGBUILD.proto b/PKGBUILD.proto index 9e4b69a0..32655306 100644 --- a/PKGBUILD.proto +++ b/PKGBUILD.proto @@ -29,7 +29,7 @@ build() { ./configure --prefix=/usr make || return 1 - make DESTDIR="$pkgdir" install + make DESTDIR="$pkgdir/" install } # vim:set ts=2 sw=2 et: diff --git a/config.guess b/config.guess index 951383e3..f2a0acfb 100755 --- a/config.guess +++ b/config.guess @@ -1,10 +1,10 @@ #! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, -# Inc. +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +# Free Software Foundation, Inc. -timestamp='2007-05-17' +timestamp='2008-01-23' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -56,8 +56,8 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 -Free Software Foundation, Inc. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -330,7 +330,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; - i86pc:SunOS:5.*:* | ix86xen:SunOS:5.*:*) + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) @@ -532,7 +532,7 @@ EOF echo rs6000-ibm-aix3.2 fi exit ;; - *:AIX:*:[45]) + *:AIX:*:[456]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 @@ -793,12 +793,15 @@ EOF exit ;; *:Interix*:[3456]*) case ${UNAME_MACHINE} in - x86) + x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; EM64T | authenticamd) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks @@ -833,7 +836,14 @@ EOF echo ${UNAME_MACHINE}-pc-minix exit ;; arm*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu @@ -954,8 +964,8 @@ EOF x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; - xtensa:Linux:*:*) - echo xtensa-unknown-linux-gnu + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so @@ -1474,9 +1484,9 @@ This script, last modified $timestamp, has failed to recognize the operating system you are using. It is advised that you download the most up to date version of the config scripts from - http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD and - http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD If the version you run ($0) is already up to date, please send the following data and any information you think might be @@ -1,10 +1,10 @@ #! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, -# Inc. +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +# Free Software Foundation, Inc. -timestamp='2007-04-29' +timestamp='2008-01-16' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software @@ -72,8 +72,8 @@ Report bugs and patches to <config-patches@gnu.org>." version="\ GNU config.sub ($timestamp) -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 -Free Software Foundation, Inc. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -369,10 +369,14 @@ case $basic_machine in | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ - | xstormy16-* | xtensa-* \ + | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-*) ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) @@ -443,6 +447,14 @@ case $basic_machine in basic_machine=ns32k-sequent os=-dynix ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; c90) basic_machine=c90-cray os=-unicos @@ -475,8 +487,8 @@ case $basic_machine in basic_machine=craynv-cray os=-unicosmp ;; - cr16c) - basic_machine=cr16c-unknown + cr16) + basic_machine=cr16-unknown os=-elf ;; crds | unos) @@ -668,6 +680,14 @@ case $basic_machine in basic_machine=m68k-isi os=-sysv ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; m88k-omron*) basic_machine=m88k-omron ;; @@ -813,6 +833,14 @@ case $basic_machine in basic_machine=i860-intel os=-osf ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; pbd) basic_machine=sparc-tti ;; @@ -1021,6 +1049,10 @@ case $basic_machine in basic_machine=tic6x-unknown os=-coff ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; tx39) basic_machine=mipstx39-unknown ;; diff --git a/configure.ac b/configure.ac index eabb4a4e..27efd170 100644 --- a/configure.ac +++ b/configure.ac @@ -51,16 +51,15 @@ m4_define([lib_revision], [1]) m4_define([lib_age], [3]) m4_define([pacman_version_major], [3]) -m4_define([pacman_version_minor], [1]) -m4_define([pacman_version_micro], [4]) -m4_define([pacman_version_suffix], []) +m4_define([pacman_version_minor], [2]) +m4_define([pacman_version_micro], [0]) +m4_define([pacman_version_suffix], [devel]) m4_define([pacman_version], [pacman_version_major.pacman_version_minor.pacman_version_micro]) m4_define([pacman_display_version], pacman_version[]m4_ifdef([pacman_version_suffix],[pacman_version_suffix])) # Autoconf initialization -# AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS) AC_INIT([Pacman Package Manager], [pacman_display_version], [pacman-dev@archlinux.org], [pacman]) AC_CONFIG_SRCDIR([config.h.in]) @@ -80,47 +79,52 @@ AC_DEFINE_UNQUOTED([LIB_VERSION], ["$LIB_VERSION"], [libalpm version number]) # Help line for root directory AC_ARG_WITH(root-dir, - AC_HELP_STRING([--with-root-dir=path], [set the location of pacman's root operating directory]), + AS_HELP_STRING([--with-root-dir=path], [set the location of pacman's root operating directory]), [ROOTDIR=$withval], [ROOTDIR=/]) # Help line for package extension AC_ARG_WITH(pkg-ext, - AC_HELP_STRING([--with-pkg-ext=ext], [set the file extension used by packages]), + AS_HELP_STRING([--with-pkg-ext=ext], [set the file extension used by packages]), [PKGEXT=$withval], [PKGEXT=.pkg.tar.gz]) # Help line for source package directory AC_ARG_WITH(src-ext, - AC_HELP_STRING([--with-src-ext=ext], [set the file extension used by source packages]), + AS_HELP_STRING([--with-src-ext=ext], [set the file extension used by source packages]), [SRCEXT=$withval], [SRCEXT=.src.tar.gz]) # Help line for database extension AC_ARG_WITH(db-ext, - AC_HELP_STRING([--with-db-ext=ext], [set the file extension used by the database]), + AS_HELP_STRING([--with-db-ext=ext], [set the file extension used by the database]), [DBEXT=$withval], [DBEXT=.db.tar.gz]) +# Help line for libdownload/libfetch +AC_ARG_ENABLE(internal-download, + AS_HELP_STRING([--disable-internal-download], [do not build with libdownload/libfetch support]), + [internaldownload=$enableval], [internaldownload=yes]) + # Help line for documentation AC_ARG_ENABLE(doc, - AC_HELP_STRING([--disable-doc], [prevent make from looking at doc/ dir]), + AS_HELP_STRING([--disable-doc], [prevent make from looking at doc/ dir]), [wantdoc=$enableval], [wantdoc=yes]) # Help line for doxygen AC_ARG_ENABLE(doxygen, - AC_HELP_STRING([--enable-doxygen], [build your own API docs via Doxygen]), + AS_HELP_STRING([--enable-doxygen], [build your own API docs via Doxygen]), [wantdoxygen=$enableval], [wantdoxygen=no]) # Help line for asciidoc AC_ARG_ENABLE(asciidoc, - AC_HELP_STRING([--enable-asciidoc], [build your own manpages with Asciidoc]), + AS_HELP_STRING([--enable-asciidoc], [build your own manpages with Asciidoc]), [wantasciidoc=$enableval], [wantasciidoc=no]) # Help line for debug AC_ARG_ENABLE(debug, - AC_HELP_STRING([--enable-debug], [enable debugging support]), + AS_HELP_STRING([--enable-debug], [enable debugging support]), [debug=$enableval], [debug=no]) # Help line for pacman.static AC_ARG_ENABLE(pacman-static, - AC_HELP_STRING([--disable-pacman-static], [do not build static version of pacman]), + AS_HELP_STRING([--disable-pacman-static], [do not build static version of pacman]), [pacmanstatic=$enableval], [pacmanstatic=yes]) # Checks for programs. @@ -129,7 +133,6 @@ AC_PROG_CC_C99 AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET -AC_PROG_RANLIB AC_PROG_LIBTOOL AC_CHECK_PROGS([PYTHON], [python2.5 python2.4 python], [false]) @@ -138,13 +141,27 @@ AM_GNU_GETTEXT([external]) AM_GNU_GETTEXT_VERSION(0.13.1) # Check for libarchive -AC_CHECK_LIB([archive], [archive_read_data], , AC_MSG_ERROR([libarchive is needed to compile pacman!])) - -# Check for libdownload -AC_CHECK_LIB([download], [downloadParseURL], , AC_MSG_ERROR([libdownload is needed to compile pacman!])) +AC_CHECK_LIB([archive], [archive_read_data], , + AC_MSG_ERROR([libarchive is needed to compile pacman!])) + +# Enable or disable usage of libdownload/libfetch +# - this is a nested check- first see if we need a library, if we do then +# check for libdownload first, then fallback to libfetch, then die +AC_MSG_CHECKING(whether to link with download library) +if test "x$internaldownload" = "xyes" ; then + AC_MSG_RESULT(yes) + AC_DEFINE([INTERNAL_DOWNLOAD], , [Use internal download library]) + # Check for a download library if it was actually requested + AC_CHECK_LIB([download], [downloadParseURL], , + AC_CHECK_LIB([fetch], [fetchParseURL], , + AC_MSG_ERROR([libdownload or libfetch are needed to compile with internal download support])) ) +else + AC_MSG_RESULT(no) +fi +AM_CONDITIONAL(INTERNAL_DOWNLOAD, test "x$internaldownload" = "xyes") # Checks for header files. -AC_CHECK_HEADERS([fcntl.h libintl.h limits.h locale.h string.h strings.h sys/ioctl.h sys/statvfs.h sys/time.h syslog.h wchar.h]) +AC_CHECK_HEADERS([fcntl.h libintl.h limits.h locale.h string.h strings.h sys/ioctl.h sys/param.h sys/statvfs.h sys/syslimits.h sys/time.h syslog.h wchar.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE @@ -156,13 +173,13 @@ AC_STRUCT_TM AC_TYPE_UID_T # Checks for library functions. -AC_FUNC_CLOSEDIR_VOID AC_FUNC_FORK AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK AC_FUNC_MKTIME AC_TYPE_SIGNAL -AC_CHECK_FUNCS([geteuid realpath regcomp strcasecmp strdup strerror \ - strndup strrchr strsep strstr strverscmp swprintf uname]) +AC_CHECK_FUNCS([geteuid realpath regcomp strcasecmp \ + strndup strrchr strsep strverscmp swprintf \ + wcwidth uname]) # Enable large file support if available AC_SYS_LARGEFILE @@ -360,6 +377,7 @@ pacman_display_version: Compilation options: Run make in doc/ dir : ${wantdoc} + Use download library : ${internaldownload} Doxygen support : ${usedoxygen} Asciidoc support : ${useasciidoc} debug support : ${debug} diff --git a/contrib/.gitignore b/contrib/.gitignore deleted file mode 100644 index e69de29b..00000000 --- a/contrib/.gitignore +++ /dev/null diff --git a/contrib/Makefile.am b/contrib/Makefile.am index 7066f409..c68ef51c 100644 --- a/contrib/Makefile.am +++ b/contrib/Makefile.am @@ -1,9 +1,12 @@ EXTRA_DIST = \ PKGBUILD.vim \ bash_completion \ + gensync \ pacdiff \ + paclist \ pacsearch \ re-pacman \ + updatesync \ vimprojects \ wget-xdelta.sh \ zsh_completion \ diff --git a/contrib/PKGBUILD.vim b/contrib/PKGBUILD.vim index 57e4cf0e..8f45ae44 100644 --- a/contrib/PKGBUILD.vim +++ b/contrib/PKGBUILD.vim @@ -151,7 +151,7 @@ hi def link pbValidSha1sums Number " options syn keyword pb_k_options options contained -syn match pbOptions /\(no\)\?\(strip\|docs\|libtool\|emptydirs\|ccache\|distcc\|makeflags\|force\)/ contained +syn match pbOptions /\(no\)\?\(strip\|docs\|libtool\|emptydirs\|zipman\|ccache\|distcc\|makeflags\|force\)/ contained syn match pbOptionsNeg /\!/ contained syn match pbOptionsDeprec /no/ contained syn region pbOptionsGroup start=/^options=(/ end=/)/ contains=pb_k_options,pbOptions,pbOptionsNeg,pbOptionsDeprec,pbIllegalOption,shDoubleQuote,shSingleQuote diff --git a/contrib/README b/contrib/README index 7eb36aae..73dbade0 100644 --- a/contrib/README +++ b/contrib/README @@ -12,6 +12,10 @@ zsh_completion - a zsh completion script, install (with a rename) to pacdiff - a simple pacnew/pacorig/pacsave updater for /etc/. +paclist - list all packages installed from a given repository. Useful for +seeing which packages you may have installed from the testing repository, +for instance. + pacsearch - a colorized search combining both -Ss and -Qs output. Installed packages are easily identified with a *** and local-only packages are also listed. @@ -24,3 +28,7 @@ vimprojects - a project file for the vim project plugin. wget-xdelta.sh - A download script for pacman which allows binary deltas generated with makepkg to be used instead of downloading full binary packages. This should cut download sizes for some package upgrades significantly. + +gensync, updatesync - The former repository management scripts that have since +been superseded by repo-add and repo-remove. They are here for posterity's +sake, and to show how repo-add and repo-remove can be wrapped in other scripts. diff --git a/contrib/bash_completion b/contrib/bash_completion index 77192858..11f021c8 100644 --- a/contrib/bash_completion +++ b/contrib/bash_completion @@ -146,14 +146,13 @@ _pacman () toparse="${a:2}" case "${arg}" in - -@(A|U|R|S|Q|h|V)) + -@(U|R|S|Q|h|V)) op="${arg/-}" mod="${mod}${a:2}" ;; --) arg="${a:2}" case "${arg}" in - add) op="A" ;; remove) op="R" ;; upgrade) op="U" ;; query) op="Q" ;; @@ -187,6 +186,7 @@ _pacman () dbonly) mod="${mod}k" ;; nosave) mod="${mod}n" ;; recursive) mod="${mod}s" ;; + unneeded) mod="${mod}u" ;; esac ;; *) toparse="${a}" ;; esac @@ -202,7 +202,6 @@ _pacman () if [ $COMP_CWORD -eq 1 ] && [[ "$cur" == -* ]]; then COMPREPLY=( $( compgen -W '\ - -A --add \ -h --help \ -Q --query \ -R --remove \ @@ -216,9 +215,10 @@ _pacman () if [[ "$cur" == -* ]]; then case "${op}" in - A|U) + U) COMPREPLY=( $( compgen -W '\ --asdeps \ + --asexplicit \ -d --nodeps \ -f --force \ -h --help \ @@ -242,6 +242,7 @@ _pacman () -k --dbonly \ -n --nosave \ -s --recursive \ + -u --unneeded \ --config \ --logfile \ --noconfirm \ @@ -257,9 +258,9 @@ _pacman () S) COMPREPLY=( $( compgen -W '\ --asdeps \ + --asexplicit \ -c --clean \ -d --nodeps \ - -e --dependsonly \ -f --force \ -g --groups \ -h --help \ @@ -316,7 +317,7 @@ _pacman () rem_selected else case "${op}" in - A|U) + U) COMPREPLY=( $( compgen -d -- "$cur" ) \ $( compgen -f -X '!*.pkg.tar.gz' -- "$cur" ) ) return 0 diff --git a/scripts/gensync.sh.in b/contrib/gensync index d5dec275..51d32ceb 100644..100755 --- a/scripts/gensync.sh.in +++ b/contrib/gensync @@ -1,7 +1,6 @@ #!/bin/bash # # gensync -# @configure_input@ # # Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org> # @@ -19,42 +18,35 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -# gettext initialization -export TEXTDOMAIN='pacman' -export TEXTDOMAINDIR='@localedir@' - -myver='@PACKAGE_VERSION@' +myver='3.1.1' # functions usage() { printf "gensync (pacman) %s\n\n" "$myver" - printf "$(gettext "Usage: %s <root> <destfile> [package_directory]")\n\n" "$0" - printf "$(gettext "\ -NOTE: this script is DEPRECATED. It will be removed in the next major\n\ -release of pacman, so please use repo-add and repo-remove instead.\n\n")" - printf "$(gettext "\ + printf "Usage: %s <root> <destfile> [package_directory]\n\n" "$0" + printf "\ gensync will generate a sync database by reading all PKGBUILD files\n\ from <root>. gensync builds the database in a temporary directory\n\ -and then compresses it to <destfile>.\n\n")" - printf "$(gettext "\ +and then compresses it to <destfile>.\n\n" + printf "\ gensync will calculate md5sums of packages in the same directory as\n\ -<destfile>, unless an alternate [package_directory] is specified.\n\n")" - printf "$(gettext "\ +<destfile>, unless an alternate [package_directory] is specified.\n\n" + printf "\ note: The <destfile> name is important. It must be of the form\n\ {treename}.db.tar.gz where {treename} is the name of the custom\n\ package repository you configured in /etc/pacman.conf. The\n\ generated database must reside in the same directory as your\n\ - custom packages (also configured in /etc/pacman.conf)\n\n")" - echo "$(gettext "Example: gensync /var/abs/local /home/mypkgs/custom.db.tar.gz")" + custom packages (also configured in /etc/pacman.conf)\n\n" + echo "Example: gensync /var/abs/local /home/mypkgs/custom.db.tar.gz" } version() { printf "gensync (pacman) %s\n" "$myver" - printf "$(gettext "\ + printf "\ Copyright (C) 2002-2007 Judd Vinet <jvinet@zeroflux.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")" +There is NO WARRANTY, to the extent permitted by law.\n" } error () { @@ -67,26 +59,8 @@ die () { exit 1 } -check_force () { - local i - for i in ${options[@]}; do - local lc=$(echo $i | tr [:upper:] [:lower:]) - if [ "$lc" = "force" ]; then - true - fi - done - false -} - # PROGRAM START -# determine whether we have gettext; make it a no-op if we do not -if [ ! $(type -t gettext) ]; then - gettext() { - echo "$@" - } -fi - if [ "$1" = "-h" -o "$1" = "--help" ]; then usage exit 0 @@ -103,10 +77,10 @@ if [ $# -lt 2 ]; then fi # source system and user makepkg.conf -if [ -r @sysconfdir@/makepkg.conf ]; then - source @sysconfdir@/makepkg.conf +if [ -r /etc/makepkg.conf ]; then + source /etc/makepkg.conf else - die "$(gettext "%s not found. Can not continue.")" "@sysconfdir@/makepkg.conf" + die "/etc/makepkg.conf not found. Cannot continue." fi if [ -r ~/.makepkg.conf ]; then @@ -124,22 +98,17 @@ if [ "$3" != "" ]; then pkgdir="$3" fi -[ ! -d "$rootdir" ] && die "$(gettext "invalid root dir: %s")" $rootdir - -printf "$(gettext "\ -NOTE: this script is DEPRECATED. It will be removed in the next major\n\ -release of pacman, so please use repo-add and repo-remove instead.\n\n")" +[ ! -d "$rootdir" ] && die "invalid root dir: $rootdir" -echo "$(gettext "gensync: building database entries, generating md5sums...")" >&2 +echo "gensync: building database entries, generating md5sums..." >&2 cd "$destdir" pkgs="" -forcepkgs="" for file in $(find "$rootdir"/* -name "$BUILDSCRIPT"); do unset pkgname pkgver pkgrel options - source $file || die "$(gettext "failed to parse %s")" $file + source $file || die "failed to parse $file" if [ "$arch" = 'any' ]; then CARCH='any' fi @@ -150,20 +119,16 @@ for file in $(find "$rootdir"/* -name "$BUILDSCRIPT"); do fi if [ ! -f "$pkgfile" ]; then - error "$(gettext "could not find %s-%s-%s-%s%s - skipping")" $pkgname $pkgver $pkgrel $CARCH $PKGEXT + error "could not find %s-%s-%s-%s%s - skipping" $pkgname $pkgver $pkgrel $CARCH $PKGEXT else - if check_force; then - forcepkgs="$forcepkgs $pkgfile" - else - pkgs="$pkgs $pkgfile" - fi + pkgs="$pkgs $pkgfile" fi done -echo "$(gettext "creating repo DB...")" +echo "creating repo DB..." # we'll trim the output just a tad, as gensync may be used on large repos -repo-add $destfile $pkgs --force $force_pkgs \ +repo-add $destfile $pkgs \ | grep -e "package" -e "database" # vim: set ts=2 sw=2 noet: diff --git a/contrib/paclist b/contrib/paclist new file mode 100755 index 00000000..0379a4c5 --- /dev/null +++ b/contrib/paclist @@ -0,0 +1,88 @@ +#!/usr/bin/perl +# paclist - List all packages installed from a given repo +# +# Copyright (C) 2008 Dan McGee <dpmcgee@gmail.com> +# +# 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 the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +use strict; +use warnings; + +my $progname = "paclist"; +my $version = "1.0"; + +if ($#ARGV != 0 || $ARGV[0] eq "--help" || $ARGV[0] eq "-h") { + print "$progname - List all packages installed from a given repo\n"; + print "Usage: $progname <repo>\n"; + print "Example: $progname testing\n"; + if ($#ARGV != 0) { + exit 1; + } + exit 0; +} + +if ( $ARGV[0] eq "--version" || $ARGV[0] eq "-v") { + print "$progname version $version\n"; + print "Copyright (C) 2008 Dan McGee\n"; + exit 0; +} + +# This hash table will be used to store pairs of ('name version', count) from +# the return of both pacman -Sl <repo> and pacman -Q output. We then check to +# see if a value was added twice (count = 2)- if so, we will print that package +# as it is both in the repo we queried and installed on our local system. +my %packages = (); +my $output; + +$output = `pacman -Sl $ARGV[0]`; +if ($? != 0) { + exit 1; +} +my @sync = split(/\n/, $output); +# sample output from pacman -Sl: +# testing foobar 1.0-1 +foreach $_ (@sync) { + my @info = split(/ /); + # we only want to store 'foobar 1.0-1' in our hash table + my $pkg = $info[1] . " " . $info[2]; + $packages{$pkg}++; +} + +$output = `pacman -Q`; +if ($? != 0) { + exit 1; +} +# sample output from pacman -Q: +# foobar 1.0-1 +my @local = split(/\n/, $output); +foreach $_ (@local) { + # store 'foobar 1.0-1' in our hash table + $packages{$_}++; +} + +# run comparison check- if value was added twice, it was in the intersection +my @intersection; +foreach $_ (keys %packages) { + if ($packages{$_} == 2) { + push @{ \@intersection }, $_; + } +} + +# print our intersection, and bask in the glory and speed of perl +@intersection = sort @intersection; +foreach $_ (@intersection) { + print $_ . "\n"; +} + +#vim: set noet: diff --git a/contrib/pacsearch b/contrib/pacsearch index c07c28a8..3cf8b925 100755 --- a/contrib/pacsearch +++ b/contrib/pacsearch @@ -1,6 +1,9 @@ -#!/bin/bash +#!/usr/bin/perl # pacsearch - Adds color and install information to a 'pacman -Ss' search # +# Copyright (C) 2008 Dan McGee <dpmcgee@gmail.com> +# +# Based off original shell script version: # Copyright (C) 2006-2007 Dan McGee <dpmcgee@gmail.com> # # This program is free software; you can redistribute it and/or @@ -18,72 +21,112 @@ #TODO: colors flag on commandline -readonly progname="pacsearch" -readonly version="1.0" +use strict; +use warnings; + +my $progname = "pacsearch"; +my $version = "2.0"; + +if ($#ARGV lt 0 || $ARGV[0] eq "--help" || $ARGV[0] eq "-h") { + print "$progname - Add color and install information to a pacman -Ss search\n"; + print "Usage: $progname <pattern>\n"; + print "Example: $progname ^gnome\n"; + if ($#ARGV lt 0) { + exit 1; + } + exit 0; +} -readonly CLR1='\\\e[0;34m' -readonly CLR2='\\\e[0;32m' -readonly CLR3='\\\e[0;35m' -readonly CLR4='\\\e[0;36m' -readonly CLR5='\\\e[0;31m' -readonly CLR6='\\\e[0;33m' -readonly CLR7='\\\e[1;36m' -readonly INST='\\\e[1;31m' -readonly BASE='\\\e[0m' +if ($ARGV[0] eq "--version" || $ARGV[0] eq "-v") { + print "$progname version $version\n"; + print "Copyright (C) 2006-2008 Dan McGee\n"; + exit 0; +} -if [ "$1" = "--help" -o "$1" = "-h" ]; then - echo "Usage: $progname <pattern>" - echo "Ex: $progname ^gnome" - exit 0 -fi +# define our colors to use when printing +my $CLR1 = "\e[0;34m"; +my $CLR2 = "\e[0;32m"; +my $CLR3 = "\e[0;35m"; +my $CLR4 = "\e[0;36m"; +my $CLR5 = "\e[0;31m"; +my $CLR6 = "\e[0;33m"; +my $CLR7 = "\e[1;36m"; +my $INST = "\e[1;31m"; +my $BASE = "\e[0m"; +my $INSTMARK = $INST."***"; -if [ "$1" = "--version" -o "$1" = "-v" ]; then - echo "$progname version $version" - echo "Copyright (C) 2006-2007 Dan McGee" - exit 0 -fi +# color a "repo/pkgname pkgver" line based on the respository name +sub to_color { + my $line = shift; + $line =~ s/(^core\/.*)/$CLR1$1$BASE/; + $line =~ s/(^extra\/.*)/$CLR2$1$BASE/; + $line =~ s/(^community\/.*)/$CLR3$1$BASE/; + $line =~ s/(^testing\/.*)/$CLR4$1$BASE/; + $line =~ s/(^unstable\/.*)/$CLR5$1$BASE/; + $line =~ s/(^custom\/.*)/$CLR6$1$BASE/; + $line =~ s/(^local\/.*)/$CLR7$1$BASE/; + # any other unknown repository + $line =~ s/(^[\w-]*\/.*)/$CLR6$1$BASE/; + return $line; +} -if [ -z "$1" -o "${1:0:1}" = "-" ]; then - echo "Usage: $progname <pattern>" - echo "Ex: $progname ^gnome" - exit 1 -fi +my %allpkgs = (); -# Make two temp files and send output of commands to these files -querydump=$(mktemp) -pacman -Qs $1 > $querydump -syncdump=$(mktemp) -pacman -Ss $1 > $syncdump +my $syncout = `pacman -Ss @ARGV`; +# split each sync search entry into its own array entry +my @syncpkgs = split(/\n^(?=\w)/m, $syncout); +# remove the extra \n from the last desc entry +if ($#syncpkgs >= 0) { + chomp($syncpkgs[$#syncpkgs]); +} -# Strip descriptions and 'local/' from -Qs query -instpkg=$(mktemp) -egrep '^[^ ]' $querydump | sed -e 's@^local/@@' > $instpkg +# counter var for packages, used here and in the query loop too +my $cnt = 0; +foreach $_ (@syncpkgs) { + # we grab 3 fields here: repo, name/ver, and desc + my @pkgfields = /^(.*?)\/(.*?)\n(.*)$/s; + # add a fourth field that will indicate install status + push (@pkgfields, ""); + # add a fifth field that indicates original order + push (@pkgfields, $cnt++); + # add each sync pkg by name/ver to a hash table for quick lookup + $allpkgs{$pkgfields[1]} = [ @pkgfields ]; +} -# Add pkgs not in sync db, mark pkgs that are installed -cat $instpkg | while read -r pkg; do - if [ -z "$(grep "$pkg" $syncdump)" ]; then - # grep package name; pipe to another grep that prints at most one - # line starting with 'local/', allows for comments >1 line - grep -A10 "$pkg" $querydump | grep -A10 -m1 "local/" >> $syncdump - fi - sed -i "s@^\(.\+/$pkg\)@\***\1@" $syncdump -done +my $queryout = `pacman -Qs @ARGV`; +# split each querysearch entry into its own array entry +my @querypkgs = split(/\n^(?=\w)/m, $queryout); +# remove the extra \n from the last desc entry +if ($#querypkgs >= 0) { + chomp ($querypkgs[$#querypkgs]); +} -# Print colorized package list and descriptions to screen -echo -e "$(sed -r \ - -e "s@core/.*@$CLR1&$BASE@" \ - -e "s@extra/.*@$CLR2&$BASE@" \ - -e "s@community/.*@$CLR3&$BASE@" \ - -e "s@testing/.*@$CLR4&$BASE@" \ - -e "s@unstable/.*@$CLR5&$BASE@" \ - -e "s@custom/.*@$CLR6&$BASE@" \ - -e "s@local/.*@$CLR7&$BASE@" \ - -e "s@(^|\*\*\*)([[:alnum:]]*/.* .*)@\1$CLR6\2$BASE@" \ - -e "s@\*\*\*@$INST&@" \ - < $syncdump )" -echo -en "\e[0m" +foreach $_ (@querypkgs) { + # we grab 3 fields here: repo, name/ver, and desc + my @pkgfields = /^(.*?)\/(.*?)\n(.*)$/s; + # check if the package was listed in the sync out + # if it is we want to mark it with a *** marker + if (exists $allpkgs{$pkgfields[1]}) { + # mark it in our fourth field as installed + @{ $allpkgs{$pkgfields[1]} }[3] = $INSTMARK; + } else { + # add a fourth field that will indicate install status + push (@pkgfields, $INSTMARK); + # add a fifth field that indicates original order (after sync) + push (@pkgfields, $cnt++); + # add our local-only package to the hash + $allpkgs{$pkgfields[1]} = [ @pkgfields ]; + } +} -rm $querydump -rm $syncdump -rm $instpkg +# sort by original order (the fifth field) and print +foreach $_ ( sort{ @{$allpkgs{$a}}[4] <=> @{$allpkgs{$b}}[4] } keys %allpkgs) { + my @v = @{$allpkgs{$_}}; + my $line = "$v[0]/$v[1]"; + $line = to_color($line); + # print install marker + colorized "repo/pkgname pkgver" string + print "$v[3]$line\n"; + print "$v[2]\n"; +} +#vim: set noet: diff --git a/scripts/updatesync.sh.in b/contrib/updatesync index 5f5cc6c9..f88e8237 100644..100755 --- a/scripts/updatesync.sh.in +++ b/contrib/updatesync @@ -1,7 +1,6 @@ #!/bin/bash # # updatesync -# @configure_input@ # # Copyright (c) 2004 by Jason Chu <jason@archlinux.org> # Derived from gensync (c) 2002-2006 Judd Vinet <jvinet@zeroflux.org> @@ -20,40 +19,33 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -# gettext initialization -export TEXTDOMAIN='pacman' -export TEXTDOMAINDIR='@localedir@' - -myver='@PACKAGE_VERSION@' +myver='3.1.1' # functions usage() { printf "updatesync (pacman) %s\n\n" "$myver" - printf "$(gettext "Usage: %s <action> <destfile> <option> [package_directory]")\n\n" "$0" - printf "$(gettext "\ -NOTE: this script is DEPRECATED. It will be removed in the next major\n\ -release of pacman, so please use repo-add and repo-remove instead.\n\n")" - printf "$(gettext "\ + printf "Usage: %s <action> <destfile> <option> [package_directory]\n\n" "$0" + printf "\ updatesync will update a sync database by reading a PKGBUILD and\n\ modifying the destfile. updatesync updates the database in a temporary\n\ -directory and then compresses it to <destfile>.\n\n")" - printf "$(gettext "There are two types of actions:\n\n")" - printf "$(gettext "upd - Will update a package's entry or create it if it doesn't exist.\n It takes the package's PKGBUILD as an option.\n")" - printf "$(gettext "del - Will remove a package's entry from the db. It takes the package's\n name as an option.\n")" +directory and then compresses it to <destfile>.\n\n" + printf "There are two types of actions:\n\n" + printf "upd - Will update a package's entry or create it if it doesn't exist.\n It takes the package's PKGBUILD as an option.\n" + printf "del - Will remove a package's entry from the db. It takes the package's\n name as an option.\n" echo - printf "$(gettext "\ + printf "\ updatesync will calculate md5sums of packages in the same directory as\n\ -<destfile>, unless an alternate [package_directory] is specified.\n\n")" - echo "$(gettext "Example: updatesync upd /home/mypkgs/custom.db.tar.gz PKGBUILD")" +<destfile>, unless an alternate [package_directory] is specified.\n\n" + echo "Example: updatesync upd /home/mypkgs/custom.db.tar.gz PKGBUILD" } version() { printf "updatesync (pacman) %s\n" "$myver" - printf "$(gettext "\ + printf "\ Copyright (C) 2004 Jason Chu <jason@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")" +There is NO WARRANTY, to the extent permitted by law.\n" } error () { @@ -66,26 +58,8 @@ die () { exit 1 } -check_force () { - local i - for i in ${options[@]}; do - local lc=$(echo $i | tr [:upper:] [:lower:]) - if [ "$lc" = "force" ]; then - true - fi - done - false -} - # PROGRAM START -# determine whether we have gettext; make it a no-op if we do not -if [ ! $(type -t gettext) ]; then - gettext() { - echo "$@" - } -fi - if [ "$1" = "-h" -o "$1" = "--help" ]; then usage exit 0 @@ -102,10 +76,10 @@ if [ $# -lt 3 ]; then fi # source system and user makepkg.conf -if [ -r @sysconfdir@/makepkg.conf ]; then - source @sysconfdir@/makepkg.conf +if [ -r /etc/makepkg.conf ]; then + source /etc/makepkg.conf else - die "$(gettext "%s not found. Can not continue.")" "@sysconfdir@/makepkg.conf" + die "/etc/makepkg.conf not found. Cannot continue." fi if [ -r ~/.makepkg.conf ]; then @@ -124,39 +98,30 @@ pkgdir="$(pwd)" if [ "$4" != "" ]; then pkgdir="$4" fi -opt_force="" - -printf "$(gettext "\ -NOTE: this script is DEPRECATED. It will be removed in the next major\n\ -release of pacman, so please use repo-add and repo-remove instead.\n\n")" if [ "$action" = "upd" ]; then # INSERT / UPDATE if [ ! -f "$option" ]; then - die "$(gettext "%s not found")" $option + die "$option not found" fi unset pkgname pkgver pkgrel options - source $option || die "$(gettext "failed to parse %s")" $option + source $option || die "failed to parse $option" if [ "$arch" = 'any' ]; then CARCH='any' fi pkgfile="$pkgdir/$pkgname-$pkgver-$pkgrel-${CARCH}${PKGEXT}" if [ ! -f "$pkgfile" ]; then - die "$(gettext "could not find %s-%s-%s-%s%s - aborting")" $pkgname $pkgver $pkgrel $CARCH $PKGEXT - fi - - if check_force; then - opt_force="--force" + die "could not find %s-%s-%s-%s%s - aborting" $pkgname $pkgver $pkgrel $CARCH $PKGEXT fi - repo-add "$pkgdb" $opt_force "$pkgfile" + repo-add "$pkgdb" "$pkgfile" else # DELETE fname="$(basename $option)" if [ "$fname" = "PKGBUILD" ]; then if [ ! -f "$option" ]; then - die "$(gettext "%s not found")" $option + die "%s not found" $option fi unset pkgname pkgver pkgrel options diff --git a/contrib/zsh_completion b/contrib/zsh_completion index 8dec06df..e1273184 100644 --- a/contrib/zsh_completion +++ b/contrib/zsh_completion @@ -6,7 +6,6 @@ typeset -A opt_args # options for passing to _arguments: main pacman commands _pacman_opts_commands=( - '-A[Add a package to the system]' '-Q[Query the package database]' '-R[Remove a package from the system]' '-S[Synchronize packages]' @@ -29,7 +28,7 @@ _pacman_opts_common=( '--noscriptlet[Do not execute the install scriptlet if one exists]' ) -# options for passing to _arguments: options for --add and --update commands +# options for passing to _arguments: options for --upgrade commands _pacman_opts_pkgfile=( '-d[Skip dependency checks]' '-f[Overwrite conflicting files]' @@ -78,7 +77,6 @@ _pacman_opts_sync_actions=( # options for passing to _arguments: options for --sync command _pacman_opts_sync_modifiers=( '-d[Skip dependency checks]' - '-e[Install dependencies only]' '-f[Overwrite conflicting files]' '-i[View package information]' '-l[List all packages in a repository]' @@ -91,15 +89,9 @@ _pacman_opts_sync_modifiers=( '*--ignoregroup[Ignore a group upgrade]:package group: _pacman_completions_all_groups' '--asdeps[Install packages as non-explicitly installed]' + '--asexplicit[Install packages as explicitly installed]' ) -# handles --action subcommand -_pacman_action_add() { - _arguments -s : \ - "$_pacman_opts_common[@]" \ - "$_pacman_opts_pkgfile[@]" -} - # handles --help subcommand _pacman_action_help() { _arguments -s : \ @@ -290,7 +282,6 @@ _pacman_get_command() { # main dispatcher _pacman() { case $words[2] in - -A*) _pacman_action_add ;; -Q*g*) # ipkg groups _arguments -s : \ "$_pacman_opts_common[@]" \ diff --git a/doc/Doxyfile b/doc/Doxyfile index 5174c651..f287bbcd 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.5.2 +# Doxyfile 1.5.5 #--------------------------------------------------------------------------- # Project related configuration options @@ -28,7 +28,8 @@ FULL_PATH_NAMES = NO STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO -JAVADOC_AUTOBRIEF = NO +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES @@ -37,10 +38,14 @@ TAB_SIZE = 4 ALIASES = OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -49,6 +54,7 @@ EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO @@ -60,6 +66,7 @@ SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO +SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES @@ -126,6 +133,10 @@ HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +HTML_DYNAMIC_SECTIONS = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO @@ -194,7 +205,9 @@ EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = ../.. INCLUDE_FILE_PATTERNS = *.h -PREDEFINED = HAVE_CONFIG_H= SYMHIDDEN= SYMEXPORT= +PREDEFINED = HAVE_CONFIG_H= \ + SYMHIDDEN= \ + SYMEXPORT= EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- @@ -227,6 +240,7 @@ DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 3 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES diff --git a/doc/PKGBUILD.5.txt b/doc/PKGBUILD.5.txt index ac394729..aa870097 100644 --- a/doc/PKGBUILD.5.txt +++ b/doc/PKGBUILD.5.txt @@ -182,6 +182,9 @@ Options and Directives *emptydirs*;; Leave empty directories in packages. + *zipman*;; + Compress man pages with gzip. + *ccache*;; Allow the use of ccache during build. More useful in its negative form `!ccache` with select packages that have problems building diff --git a/doc/makepkg.8.txt b/doc/makepkg.8.txt index 59108f1b..068cbcb5 100644 --- a/doc/makepkg.8.txt +++ b/doc/makepkg.8.txt @@ -45,13 +45,6 @@ Options for rebuilding packages from source when the PKGBUILD may be slightly outdated and not updated with an `$$arch=('yourarch')$$` field. -*-b, \--builddeps*:: - Build missing dependencies from source. When makepkg finds missing - build-time or run-time dependencies, it will look for the dependencies' - PKGBUILD files under `SRCROOT` (set in linkman:makepkg.conf[5]). If it - finds them it will call makepkg to build and install the missing - dependencies. The child calls will be made with the `-b` and `-i` options. - *-c, \--clean*:: Clean up leftover work files and directories after a successful build. diff --git a/doc/makepkg.conf.5.txt b/doc/makepkg.conf.5.txt index f6e4b382..113ad140 100644 --- a/doc/makepkg.conf.5.txt +++ b/doc/makepkg.conf.5.txt @@ -37,6 +37,9 @@ Options well; the download URL is placed on the end of the command. This is more flexible than the former `FTPAGENT` variable, as any protocol can have a download agent. Several examples are provided in the default makepkg.conf. + All instances of `%u` will be replaced with the download URL. If present, + instances of `%o` will be replaced with the local filename, plus a ``.part'' + extension, which allows to do file resumes properly. **CARCH=**"carch":: Specifies your computer architecture; possible values include such things @@ -94,8 +97,8 @@ Options running in the DistCC cluster. In addition, you will want to modify your `MAKEFLAGS`. -**OPTIONS=(**strip !docs libtool emptydirs**)**:: - This array contains options that affect the default packaging. All four are +**OPTIONS=(**strip !docs libtool emptydirs zipman**)**:: + This array contains options that affect the default packaging. They are equivalent to options that can be placed in the PKGBUILD; the defaults are shown here. All options should always be left in the array; to enable or disable an option simply remove or place an ``!'' at the front of the @@ -117,6 +120,9 @@ Options *emptydirs*;; Leave empty directories in packages. + *zipman*;; + Compress man pages with gzip. + **INTEGRITY_CHECK=(**check1 ...**)**:: File integrity checks to use. Multiple checks may be specified; this affects both generation and checking. The current valid options are: diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt index f6eb69c3..a6bc3d9a 100644 --- a/doc/pacman.8.txt +++ b/doc/pacman.8.txt @@ -28,13 +28,6 @@ ends to be written (for instance, a GUI front end). Operations ---------- -*-A, \--add* (deprecated):: - Add a package to the system. Either a URL or file path can be specified. - The package will be uncompressed into the installation root and the - database will be updated. The package will not be installed if another - version is already installed. *NOTE*: please use '\--upgrade' in place of - this option. - *-Q, \--query*:: Query the package database. This operation allows you to view installed packages and their files, as well as meta-information about individual @@ -86,11 +79,17 @@ You can also use `pacman -Su` to upgrade all packages that are out of date. See Options ------- *\--asdeps*:: - Install packages non-explicitly; in other works, fake their install reason + Install packages non-explicitly; in other words, fake their install reason to be installed as a dependency. This is useful for makepkg and other build from source tools that need to install dependencies before building the package. +*\--asexplicit*:: + Install packages explicitly; in other words, fake their install reason to + be explicitly installed. This is useful if you want to mark a dependency + as explicitly installed so it will not be removed by the '\--recursive' + remove operation. + *-b, \--dbpath* <'path'>:: Specify an alternative database location (a typical default is ``/var/lib/pacman''). This should not be used unless you know what you are @@ -226,7 +225,12 @@ Remove Options[[RO]] that (A) they are not required by other packages; and (B) they were not explicitly installed by the user. This operation is recursive and analogous to a backwards '\--sync' operation, and helps keep a clean system without - orphans. + orphans. If you want to omit condition (B), pass this option twice. + +*-u, \--unneeded*:: + Removes the targets that are not required by any other packages. + This is mostly useful when removing a group without using the '-c' option, + to avoid breaking any dependencies. Sync Options[[SO]] @@ -241,10 +245,9 @@ Sync Options[[SO]] packages that are no longer installed; use two to remove all packages from the cache. In both cases, you will have a yes or no option to remove packages and/or unused downloaded databases. - -*-e, \--dependsonly*:: - Install all dependencies of a package, but not the specified package - itself. This is pretty useless and we're not sure why it even exists. ++ +If you use a network shared cache, see the 'CleanMethod' option in +linkman:pacman.conf[5]. *-g, \--groups*:: Display all the members for each package group specified. If no group diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt index cb9d2c55..eb9285c3 100644 --- a/doc/pacman.conf.5.txt +++ b/doc/pacman.conf.5.txt @@ -40,6 +40,8 @@ Include = /etc/pacman.d/core Server = file:///home/pkgs -------- +*NOTE*: Each directive must be in CamelCase. If the case isn't respected, the directive +won't be recognized. For example. noupgrade or NOUPGRADE will not work. Options ------- @@ -80,6 +82,12 @@ Options Instructs pacman to ignore any upgrades for this package when performing a '\--sysupgrade'. +*SyncFirst =* package ...:: + Instructs pacman to check for newer version of these packages before any + sync operation. The user will have the choice to either cancel the current + operation and upgrade these packages first or go on with the current operation. + This option is typically used with the 'pacman' package. + *IgnoreGroup =* group ...:: Instructs pacman to ignore any upgrades for all packages in this group when performing a '\--sysupgrade'. @@ -117,6 +125,15 @@ Options These files refer to files in the package archive, so do not include the leading slash (the RootDir) when specifying them. +*CleanMethod =* KeepInstalled | KeepCurrent:: + If set to `KeepInstalled` (the default), the '-Sc' operation will clean + packages that are no longer installed (not present in the local database). + If set to `KeepCurrent`, '-Sc' will clean outdated packages (not present in + any sync database). + The second behavior is useful when the package cache is shared among + multiple machines, where the local databases are usually different, but the + sync databases in use could be the same. + *UseSyslog*:: Log action messages through syslog(). This will insert log entries into ``/var/log/messages'' or equivalent. diff --git a/doc/repo-add.8.txt b/doc/repo-add.8.txt index 5664949f..d3b85762 100644 --- a/doc/repo-add.8.txt +++ b/doc/repo-add.8.txt @@ -16,9 +16,9 @@ repo-add - package database maintenance utility Synopsis -------- -repo-add <path-to-db> [--force] <package> ... +repo-add [-q] <path-to-db> <package> ... -repo-remove <path-to-db> <packagename> ... +repo-remove [-q] <path-to-db> <packagename> ... Description @@ -36,12 +36,9 @@ on the command line. Options ------- -*--force* (repo-add only):: - Add a force entry to the sync database, which tells pacman to skip version - number comparison and update the package regardless. This flag can be - specified in the middle of the command line, with any packages listed - before the flag being added as normal entries, and any specified after - being marked as force upgrades. +*-q, \--quiet*:: + Force this program to keep quiet and run silent except for warning and + error messages. See Also diff --git a/etc/makepkg.conf.in b/etc/makepkg.conf.in index 4da4a63d..47ed0a45 100644 --- a/etc/makepkg.conf.in +++ b/etc/makepkg.conf.in @@ -8,11 +8,11 @@ # #-- The download utilities that makepkg should use to acquire sources # Format: 'protocol::agent' -DLAGENTS=('ftp::/usr/bin/wget -c --passive-ftp -t 3 --waitretry=3' - 'http::/usr/bin/wget -c -t 3 --waitretry=3' - 'https::/usr/bin/wget -c -t 3 --waitretry=3 --no-check-certificate' - 'rsync::/usr/bin/rsync -z' - 'scp::/usr/bin/scp -C') +DLAGENTS=('ftp::/usr/bin/wget -c --passive-ftp -t 3 --waitretry=3 -O %o %u' + 'http::/usr/bin/wget -c -t 3 --waitretry=3 -O %o %u' + 'https::/usr/bin/wget -c -t 3 --waitretry=3 --no-check-certificate -O %o %u' + 'rsync::/usr/bin/rsync -z %u %o' + 'scp::/usr/bin/scp -C %u %o') # Other common tools: # /usr/bin/snarf @@ -58,15 +58,16 @@ BUILDENV=(fakeroot !distcc color !ccache !xdelta) # These are default values for the options=() settings ######################################################################### # -# Default: OPTIONS=(strip !docs libtool emptydirs) +# Default: OPTIONS=(strip !docs libtool emptydirs zipman) # A negated option will do the opposite of the comments below. # #-- strip: Strip symbols from binaries/libraries #-- docs: Save doc and info directories #-- libtool: Leave libtool (.la) files in packages #-- emptydirs: Leave empty directories in packages +#-- zipman: Compress manpages with gzip # -OPTIONS=(strip !docs libtool emptydirs) +OPTIONS=(strip !docs libtool emptydirs zipman) #-- File integrity checks to use. Valid: md5, sha1, sha256, sha384, sha512 INTEGRITY_CHECK=(md5) @@ -83,8 +84,6 @@ DOC_DIRS=(usr/{,share/}{info,doc,gtk-doc} opt/*/{info,doc,gtk-doc}) #PKGDEST=/home/packages #-- Source cache: specify a fixed directory where source files will be cached #SRCDEST=/home/sources -#-- Source root: specify location where PKGBUILDs are located for '--builddeps' -#SRCROOT=/home/pkgbuilds #-- Packager: name/email of the person or organization building packages #PACKAGER="John Doe <john@doe.com>" diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am index 14d42a0c..871855ef 100644 --- a/lib/libalpm/Makefile.am +++ b/lib/libalpm/Makefile.am @@ -26,19 +26,21 @@ libalpm_la_SOURCES = \ alpm_list.h alpm_list.c \ backup.h backup.c \ be_files.c \ + be_package.c \ cache.h cache.c \ conflict.h conflict.c \ db.h db.c \ delta.h delta.c \ deps.h deps.c \ - error.h error.c \ + dload.h dload.c \ + error.c \ + graph.h \ group.h group.c \ handle.h handle.c \ log.h log.c \ md5.h md5.c \ package.h package.c \ remove.h remove.c \ - server.h server.c \ sync.h sync.c \ trans.h trans.c \ util.h util.c diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index 0a1a1924..c5454bab 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -37,7 +37,6 @@ #include "alpm_list.h" #include "trans.h" #include "util.h" -#include "error.h" #include "cache.h" #include "log.h" #include "backup.h" @@ -68,41 +67,25 @@ int _alpm_add_loadtarget(pmtrans_t *trans, pmdb_t *db, char *name) pkgname = alpm_pkg_get_name(pkg); pkgver = alpm_pkg_get_version(pkg); - if(trans->type != PM_TRANS_TYPE_UPGRADE) { - /* only install this package if it is not already installed */ - if(_alpm_db_get_pkgfromcache(db, pkgname)) { - pm_errno = PM_ERR_PKG_INSTALLED; - goto error; - } - } - /* check if an older version of said package is already in transaction * packages. if so, replace it in the list */ for(i = trans->packages; i; i = i->next) { - pmpkg_t *pkg = i->data; - if(strcmp(pkg->name, pkgname) == 0) { - if(_alpm_versioncmp(pkg->version, pkgver) < 0) { - pmpkg_t *newpkg; + pmpkg_t *transpkg = i->data; + if(strcmp(transpkg->name, pkgname) == 0) { + if(alpm_pkg_vercmp(transpkg->version, pkgver) < 0) { _alpm_log(PM_LOG_WARNING, _("replacing older version %s-%s by %s in target list\n"), - pkg->name, pkg->version, pkgver); - if((newpkg = _alpm_pkg_load(name, 1)) == NULL) { - /* pm_errno is already set by pkg_load() */ - goto error; - } + transpkg->name, transpkg->version, pkgver); _alpm_pkg_free(i->data); - i->data = newpkg; + i->data = pkg; } else { - _alpm_log(PM_LOG_WARNING, _("newer version %s-%s is in the target list -- skipping\n"), - pkg->name, pkg->version); + _alpm_log(PM_LOG_WARNING, _("skipping %s-%s because newer version %s is in the target list\n"), + pkgname, pkgver, transpkg->version); + _alpm_pkg_free(pkg); } return(0); } } - if(trans->flags & PM_TRANS_FLAG_ALLDEPS) { - pkg->reason = PM_PKG_REASON_DEPEND; - } - /* add the package to the transaction */ trans->packages = alpm_list_add(trans->packages, pkg); @@ -113,15 +96,6 @@ error: return(-1); } - -/* This is still messy. We have a lot of compare functions, and we should - * try to consolidate them as much as we can (between add and sync) */ -/*static int deppkg_cmp(const void *p1, const void *p2) -{ - return(strcmp(((pmdepmissing_t *)p1)->target, - ((pmdepmissing_t *)p2)->target)); -}*/ - int _alpm_add_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data) { alpm_list_t *lp = NULL; @@ -138,12 +112,13 @@ int _alpm_add_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data) /* look for unsatisfied dependencies */ _alpm_log(PM_LOG_DEBUG, "looking for unsatisfied dependencies\n"); - lp = alpm_checkdeps(db, trans->type == PM_TRANS_TYPE_UPGRADE, NULL, trans->packages); + lp = alpm_checkdeps(db, 1, NULL, trans->packages); if(lp != NULL) { if(data) { *data = lp; } else { - FREELIST(lp); + alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free); + alpm_list_free(lp); } RET_ERR(PM_ERR_UNSATISFIED_DEPS, -1); } @@ -167,7 +142,7 @@ int _alpm_add_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data) _alpm_log(PM_LOG_ERROR, _("you cannot install two conflicting packages at the same time\n")); } if(outer) { - _alpm_log(PM_LOG_ERROR, _("replacing packages with -A and -U is not supported yet\n")); + _alpm_log(PM_LOG_ERROR, _("replacing packages with -U is not supported yet\n")); _alpm_log(PM_LOG_ERROR, _("you can replace packages manually using -Rd and -U\n")); } RET_ERR(PM_ERR_CONFLICTING_DEPS, -1); @@ -175,7 +150,7 @@ int _alpm_add_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data) /* re-order w.r.t. dependencies */ _alpm_log(PM_LOG_DEBUG, "sorting by dependencies\n"); - lp = _alpm_sortbydeps(trans->packages, PM_TRANS_TYPE_ADD); + lp = _alpm_sortbydeps(trans->packages, 0); /* free the old alltargs */ alpm_list_free(trans->packages); trans->packages = lp; @@ -193,7 +168,8 @@ int _alpm_add_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data) if(data) { *data = lp; } else { - FREELIST(lp); + alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_fileconflict_free); + alpm_list_free(lp); } RET_ERR(PM_ERR_FILE_CONFLICTS, -1); } @@ -210,6 +186,9 @@ static int upgrade_remove(pmpkg_t *oldpkg, pmpkg_t *newpkg, pmtrans_t *trans, pm * with the type PM_TRANS_TYPE_REMOVEUPGRADE. TODO: kill this weird * behavior. */ pmtrans_t *tr = _alpm_trans_new(); + + ALPM_LOG_FUNC; + _alpm_log(PM_LOG_DEBUG, "removing old package first (%s-%s)\n", oldpkg->name, oldpkg->version); @@ -290,17 +269,18 @@ static int extract_single_file(struct archive *archive, struct archive_entry *entry, pmpkg_t *newpkg, pmpkg_t *oldpkg, pmtrans_t *trans, pmdb_t *db) { - char entryname[PATH_MAX]; /* the name of the file in the archive */ + const char *entryname; mode_t entrymode; char filename[PATH_MAX]; /* the actual file we're extracting */ int needbackup = 0, notouch = 0; char *hash_orig = NULL; + char *entryname_orig = NULL; const int archive_flags = ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME; int errors = 0; - strncpy(entryname, archive_entry_pathname(entry), PATH_MAX); + entryname = archive_entry_pathname(entry); entrymode = archive_entry_mode(entry); memset(filename, 0, PATH_MAX); /* just to be sure */ @@ -338,7 +318,8 @@ static int extract_single_file(struct archive *archive, /* if a file is in the add skiplist we never extract it */ if(alpm_list_find_str(trans->skip_add, filename)) { - _alpm_log(PM_LOG_DEBUG, "%s is in trans->skip_add, skipping extraction\n", entryname); + _alpm_log(PM_LOG_DEBUG, "%s is in trans->skip_add, skipping extraction\n", + entryname); archive_read_data_skip(archive); return(0); } @@ -437,7 +418,7 @@ static int extract_single_file(struct archive *archive, /* if we force hash_orig to be non-NULL retroactive backup works */ if(needbackup && !hash_orig) { - hash_orig = strdup(""); + STRDUP(hash_orig, "", RET_ERR(PM_ERR_MEMORY, -1)); } } } @@ -445,34 +426,35 @@ static int extract_single_file(struct archive *archive, /* case 5,8: don't need to do anything special */ } + /* we need access to the original entryname later after calls to + * archive_entry_set_pathname(), so we need to dupe it and free() later */ + STRDUP(entryname_orig, entryname, RET_ERR(PM_ERR_MEMORY, -1)); + if(needbackup) { - char *tempfile; + char checkfile[PATH_MAX]; char *hash_local = NULL, *hash_pkg = NULL; - int fd; + int ret; - /* extract the package's version to a temporary file and checksum it */ - tempfile = strdup("/tmp/alpm_XXXXXX"); - fd = mkstemp(tempfile); + snprintf(checkfile, PATH_MAX, "%s.paccheck", filename); + archive_entry_set_pathname(entry, checkfile); - int ret = archive_read_data_into_fd(archive, fd); - close(fd); + ret = archive_read_extract(archive, entry, archive_flags); if(ret == ARCHIVE_WARN) { /* operation succeeded but a non-critical error was encountered */ _alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n", - entryname, archive_error_string(archive)); + entryname_orig, archive_error_string(archive)); } else if(ret != ARCHIVE_OK) { _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), - entryname, archive_error_string(archive)); + entryname_orig, archive_error_string(archive)); alpm_logaction("error: could not extract %s (%s)\n", - entryname, archive_error_string(archive)); - unlink(tempfile); - FREE(tempfile); + entryname_orig, archive_error_string(archive)); FREE(hash_orig); + FREE(entryname_orig); return(1); } hash_local = alpm_get_md5sum(filename); - hash_pkg = alpm_get_md5sum(tempfile); + hash_pkg = alpm_get_md5sum(checkfile); /* append the new md5 hash to it's respective entry * in newpkg's backup (it will be the new orginal) */ @@ -480,16 +462,13 @@ static int extract_single_file(struct archive *archive, for(backups = alpm_pkg_get_backup(newpkg); backups; backups = alpm_list_next(backups)) { char *oldbackup = alpm_list_getdata(backups); - if(!oldbackup || strcmp(oldbackup, entryname) != 0) { + if(!oldbackup || strcmp(oldbackup, entryname_orig) != 0) { continue; } char *backup = NULL; /* length is tab char, null byte and MD5 (32 char) */ - int backup_len = strlen(oldbackup) + 34; - backup = malloc(backup_len); - if(!backup) { - RET_ERR(PM_ERR_MEMORY, -1); - } + size_t backup_len = strlen(oldbackup) + 34; + MALLOC(backup, backup_len, RET_ERR(PM_ERR_MEMORY, -1)); sprintf(backup, "%s\t%s", oldbackup, hash_pkg); backup[backup_len-1] = '\0'; @@ -497,7 +476,7 @@ static int extract_single_file(struct archive *archive, backups->data = backup; } - _alpm_log(PM_LOG_DEBUG, "checking hashes for %s\n", entryname); + _alpm_log(PM_LOG_DEBUG, "checking hashes for %s\n", entryname_orig); _alpm_log(PM_LOG_DEBUG, "current: %s\n", hash_local); _alpm_log(PM_LOG_DEBUG, "new: %s\n", hash_pkg); _alpm_log(PM_LOG_DEBUG, "original: %s\n", hash_orig); @@ -511,19 +490,20 @@ static int extract_single_file(struct archive *archive, /* move the existing file to the "pacorig" */ if(rename(filename, newpath)) { - archive_entry_set_pathname(entry, filename); - _alpm_log(PM_LOG_ERROR, _("could not rename %s (%s)\n"), filename, strerror(errno)); - alpm_logaction("error: could not rename %s (%s)\n", filename, strerror(errno)); + _alpm_log(PM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), + filename, newpath, strerror(errno)); + alpm_logaction("error: could not rename %s to %s (%s)\n", + filename, newpath, strerror(errno)); errors++; } else { - /* copy the tempfile we extracted to the real path */ - if(_alpm_copyfile(tempfile, filename)) { - archive_entry_set_pathname(entry, filename); - _alpm_log(PM_LOG_ERROR, _("could not copy tempfile to %s (%s)\n"), filename, strerror(errno)); - alpm_logaction("error: could not copy tempfile to %s (%s)\n", filename, strerror(errno)); + /* rename the file we extracted to the real name */ + if(rename(checkfile, filename)) { + _alpm_log(PM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), + checkfile, filename, strerror(errno)); + alpm_logaction("error: could not rename %s to %s (%s)\n", + checkfile, filename, strerror(errno)); errors++; } else { - archive_entry_set_pathname(entry, filename); _alpm_log(PM_LOG_WARNING, _("%s saved as %s\n"), filename, newpath); alpm_logaction("warning: %s saved as %s\n", filename, newpath); } @@ -536,38 +516,48 @@ static int extract_single_file(struct archive *archive, /* installed file has NOT been changed by user */ if(strcmp(hash_orig, hash_pkg) != 0) { _alpm_log(PM_LOG_DEBUG, "action: installing new file: %s\n", - entryname); + entryname_orig); - if(_alpm_copyfile(tempfile, filename)) { - _alpm_log(PM_LOG_ERROR, _("could not copy tempfile to %s (%s)\n"), filename, strerror(errno)); + if(rename(checkfile, filename)) { + _alpm_log(PM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), + checkfile, filename, strerror(errno)); + alpm_logaction("error: could not rename %s to %s (%s)\n", + checkfile, filename, strerror(errno)); errors++; } - archive_entry_set_pathname(entry, filename); } else { /* there's no sense in installing the same file twice, install * ONLY is the original and package hashes differ */ _alpm_log(PM_LOG_DEBUG, "action: leaving existing file in place\n"); + unlink(checkfile); } } else if(strcmp(hash_orig, hash_pkg) == 0) { /* originally installed file and new file are the same - this * implies the case above failed - i.e. the file was changed by a * user */ _alpm_log(PM_LOG_DEBUG, "action: leaving existing file in place\n"); + unlink(checkfile); } else if(strcmp(hash_local, hash_pkg) == 0) { /* this would be magical. The above two cases failed, but the * user changes just so happened to make the new file exactly the * same as the one in the package... skip it */ _alpm_log(PM_LOG_DEBUG, "action: leaving existing file in place\n"); + unlink(checkfile); } else { char newpath[PATH_MAX]; - _alpm_log(PM_LOG_DEBUG, "action: keeping current file and installing new one with .pacnew ending\n"); + _alpm_log(PM_LOG_DEBUG, "action: keeping current file and installing" + " new one with .pacnew ending\n"); snprintf(newpath, PATH_MAX, "%s.pacnew", filename); - if(_alpm_copyfile(tempfile, newpath)) { - _alpm_log(PM_LOG_ERROR, _("could not install %s as %s: %s\n"), filename, newpath, strerror(errno)); - alpm_logaction("error: could not install %s as %s: %s\n", filename, newpath, strerror(errno)); + if(rename(checkfile, newpath)) { + _alpm_log(PM_LOG_ERROR, _("could not install %s as %s (%s)\n"), + filename, newpath, strerror(errno)); + alpm_logaction("error: could not install %s as %s (%s)\n", + filename, newpath, strerror(errno)); } else { - _alpm_log(PM_LOG_WARNING, _("%s installed as %s\n"), filename, newpath); - alpm_logaction("warning: %s installed as %s\n", filename, newpath); + _alpm_log(PM_LOG_WARNING, _("%s installed as %s\n"), + filename, newpath); + alpm_logaction("warning: %s installed as %s\n", + filename, newpath); } } } @@ -575,9 +565,9 @@ static int extract_single_file(struct archive *archive, FREE(hash_local); FREE(hash_pkg); FREE(hash_orig); - unlink(tempfile); - FREE(tempfile); } else { + int ret; + /* we didn't need a backup */ if(notouch) { /* change the path to a .pacnew extension */ @@ -598,16 +588,17 @@ static int extract_single_file(struct archive *archive, archive_entry_set_pathname(entry, filename); - int ret = archive_read_extract(archive, entry, archive_flags); + ret = archive_read_extract(archive, entry, archive_flags); if(ret == ARCHIVE_WARN) { /* operation succeeded but a non-critical error was encountered */ _alpm_log(PM_LOG_DEBUG, "warning extracting %s (%s)\n", - entryname, archive_error_string(archive)); + entryname_orig, archive_error_string(archive)); } else if(ret != ARCHIVE_OK) { _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)\n"), - entryname, archive_error_string(archive)); + entryname_orig, archive_error_string(archive)); alpm_logaction("error: could not extract %s (%s)\n", - entryname, archive_error_string(archive)); + entryname_orig, archive_error_string(archive)); + FREE(entryname_orig); return(1); } @@ -617,18 +608,15 @@ static int extract_single_file(struct archive *archive, char *backup = NULL, *hash = NULL; char *oldbackup = alpm_list_getdata(b); /* length is tab char, null byte and MD5 (32 char) */ - int backup_len = strlen(oldbackup) + 34; + size_t backup_len = strlen(oldbackup) + 34; - if(!oldbackup || strcmp(oldbackup, entryname) != 0) { + if(!oldbackup || strcmp(oldbackup, entryname_orig) != 0) { continue; } _alpm_log(PM_LOG_DEBUG, "appending backup entry for %s\n", filename); hash = alpm_get_md5sum(filename); - backup = malloc(backup_len); - if(!backup) { - RET_ERR(PM_ERR_MEMORY, -1); - } + MALLOC(backup, backup_len, RET_ERR(PM_ERR_MEMORY, -1)); sprintf(backup, "%s\t%s", oldbackup, hash); backup[backup_len-1] = '\0'; @@ -637,6 +625,7 @@ static int extract_single_file(struct archive *archive, b->data = backup; } } + FREE(entryname_orig); return(errors); } @@ -644,14 +633,13 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, pmtrans_t *trans, pmdb_t *db) { int i, ret = 0, errors = 0; - struct archive *archive; - struct archive_entry *entry; - char cwd[PATH_MAX] = ""; char scriptlet[PATH_MAX+1]; int is_upgrade = 0; double percent = 0.0; pmpkg_t *oldpkg = NULL; + ALPM_LOG_FUNC; + snprintf(scriptlet, PATH_MAX, "%s%s-%s/install", db->path, alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg)); @@ -666,12 +654,8 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, /* we'll need to save some record for backup checks later */ oldpkg = _alpm_pkg_dup(local); - /* copy over the install reason (unless alldeps is set) */ - if(trans->flags & PM_TRANS_FLAG_ALLDEPS) { - newpkg->reason = PM_PKG_REASON_DEPEND; - } else { + /* copy over the install reason */ newpkg->reason = alpm_pkg_get_reason(local); - } /* pre_upgrade scriptlet */ if(alpm_pkg_has_scriptlet(newpkg) && !(trans->flags & PM_TRANS_FLAG_NOSCRIPTLET)) { @@ -692,6 +676,13 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, } } + /* we override any pre-set reason if we have alldeps or allexplicit set */ + if(trans->flags & PM_TRANS_FLAG_ALLDEPS) { + newpkg->reason = PM_PKG_REASON_DEPEND; + } else if(trans->flags & PM_TRANS_FLAG_ALLEXPLICIT) { + newpkg->reason = PM_PKG_REASON_EXPLICIT; + } + if(oldpkg) { /* set up fake remove transaction */ int ret = upgrade_remove(oldpkg, newpkg, trans, db); @@ -701,15 +692,20 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, } if(!(trans->flags & PM_TRANS_FLAG_DBONLY)) { + struct archive *archive; + struct archive_entry *entry; + char cwd[PATH_MAX] = ""; + _alpm_log(PM_LOG_DEBUG, "extracting files\n"); if ((archive = archive_read_new()) == NULL) { - RET_ERR(PM_ERR_LIBARCHIVE_ERROR, -1); + RET_ERR(PM_ERR_LIBARCHIVE, -1); } archive_read_support_compression_all(archive); archive_read_support_format_all(archive); + _alpm_log(PM_LOG_DEBUG, "archive: %s\n", newpkg->origin_data.file); if(archive_read_open_filename(archive, newpkg->origin_data.file, ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { RET_ERR(PM_ERR_PKG_OPEN, -1); @@ -810,7 +806,6 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, PROGRESS(trans, PM_TRANS_PROGRESS_ADD_START, alpm_pkg_get_name(newpkg), 100, pkg_count, pkg_current); } - EVENT(trans, PM_TRANS_EVT_EXTRACT_DONE, NULL, NULL); /* run the post-install script if it exists */ if(alpm_pkg_has_scriptlet(newpkg) @@ -850,7 +845,7 @@ int _alpm_add_commit(pmtrans_t *trans, pmdb_t *db) return(0); } - pkg_count = alpm_list_count(trans->targets); + pkg_count = alpm_list_count(trans->packages); pkg_current = 1; /* loop through our package list adding/upgrading one at a time */ diff --git a/lib/libalpm/alpm.c b/lib/libalpm/alpm.c index fb19d076..ee29d534 100644 --- a/lib/libalpm/alpm.c +++ b/lib/libalpm/alpm.c @@ -25,7 +25,6 @@ /* libalpm */ #include "alpm.h" #include "alpm_list.h" -#include "error.h" #include "handle.h" #include "util.h" diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 96b63ca6..62a517b4 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -45,14 +45,12 @@ typedef struct __pmdb_t pmdb_t; typedef struct __pmpkg_t pmpkg_t; typedef struct __pmdelta_t pmdelta_t; typedef struct __pmgrp_t pmgrp_t; -typedef struct __pmserver_t pmserver_t; typedef struct __pmtrans_t pmtrans_t; typedef struct __pmsyncpkg_t pmsyncpkg_t; typedef struct __pmdepend_t pmdepend_t; typedef struct __pmdepmissing_t pmdepmissing_t; typedef struct __pmconflict_t pmconflict_t; typedef struct __pmfileconflict_t pmfileconflict_t; -typedef struct __pmgraph_t pmgraph_t; /* * Library @@ -81,8 +79,7 @@ int alpm_logaction(char *fmt, ...); * Downloading */ -typedef void (*alpm_cb_download)(const char *filename, int file_xfered, - int file_total, int list_xfered, int list_total); +typedef void (*alpm_cb_download)(const char *filename, int xfered, int total); /* * Options @@ -170,7 +167,6 @@ int alpm_db_update(int level, pmdb_t *db); pmpkg_t *alpm_db_get_pkg(pmdb_t *db, const char *name); alpm_list_t *alpm_db_getpkgcache(pmdb_t *db); -alpm_list_t *alpm_db_whatprovides(pmdb_t *db, const char *name); pmgrp_t *alpm_db_readgrp(pmdb_t *db, const char *name); alpm_list_t *alpm_db_getgrpcache(pmdb_t *db); @@ -192,7 +188,7 @@ int alpm_pkg_load(const char *filename, unsigned short full, pmpkg_t **pkg); int alpm_pkg_free(pmpkg_t *pkg); int alpm_pkg_checkmd5sum(pmpkg_t *pkg); char *alpm_fetch_pkgurl(const char *url); -int alpm_pkg_vercmp(const char *ver1, const char *ver2); +int alpm_pkg_vercmp(const char *a, const char *b); alpm_list_t *alpm_pkg_compute_requiredby(pmpkg_t *pkg); const char *alpm_pkg_get_filename(pmpkg_t *pkg); @@ -225,38 +221,33 @@ size_t alpm_pkg_changelog_read(void *ptr, size_t size, int alpm_pkg_changelog_close(const pmpkg_t *pkg, void *fp); unsigned short alpm_pkg_has_scriptlet(pmpkg_t *pkg); -unsigned long alpm_pkg_download_size(pmpkg_t *newpkg, pmdb_t *db_local); +unsigned long alpm_pkg_download_size(pmpkg_t *newpkg); /* * Deltas */ const char *alpm_delta_get_from(pmdelta_t *delta); +const char *alpm_delta_get_from_md5sum(pmdelta_t *delta); const char *alpm_delta_get_to(pmdelta_t *delta); -unsigned long alpm_delta_get_size(pmdelta_t *delta); +const char *alpm_delta_get_to_md5sum(pmdelta_t *delta); const char *alpm_delta_get_filename(pmdelta_t *delta); const char *alpm_delta_get_md5sum(pmdelta_t *delta); +unsigned long alpm_delta_get_size(pmdelta_t *delta); /* * Groups */ const char *alpm_grp_get_name(const pmgrp_t *grp); -const alpm_list_t *alpm_grp_get_pkgs(const pmgrp_t *grp); +alpm_list_t *alpm_grp_get_pkgs(const pmgrp_t *grp); /* * Sync */ -/* Types */ -typedef enum _pmsynctype_t { - PM_SYNC_TYPE_REPLACE = 1, - PM_SYNC_TYPE_UPGRADE, - PM_SYNC_TYPE_DEPEND -} pmsynctype_t; - -pmsynctype_t alpm_sync_get_type(const pmsyncpkg_t *sync); pmpkg_t *alpm_sync_get_pkg(const pmsyncpkg_t *sync); -void *alpm_sync_get_data(const pmsyncpkg_t *sync); +alpm_list_t *alpm_sync_get_removes(const pmsyncpkg_t *sync); +pmpkg_t *alpm_sync_newversion(pmpkg_t *pkg, alpm_list_t *dbs_sync); int alpm_sync_sysupgrade(pmdb_t *db_local, alpm_list_t *dbs_sync, alpm_list_t **syncpkgs); @@ -266,10 +257,9 @@ int alpm_sync_sysupgrade(pmdb_t *db_local, /* Types */ typedef enum _pmtranstype_t { - PM_TRANS_TYPE_ADD = 1, + PM_TRANS_TYPE_UPGRADE = 1, PM_TRANS_TYPE_REMOVE, PM_TRANS_TYPE_REMOVEUPGRADE, - PM_TRANS_TYPE_UPGRADE, PM_TRANS_TYPE_SYNC } pmtranstype_t; @@ -282,45 +272,103 @@ typedef enum _pmtransflag_t { PM_TRANS_FLAG_CASCADE = 0x10, PM_TRANS_FLAG_RECURSE = 0x20, PM_TRANS_FLAG_DBONLY = 0x40, - PM_TRANS_FLAG_DEPENDSONLY = 0x80, + /* 0x80 flag can go here */ PM_TRANS_FLAG_ALLDEPS = 0x100, PM_TRANS_FLAG_DOWNLOADONLY = 0x200, PM_TRANS_FLAG_NOSCRIPTLET = 0x400, PM_TRANS_FLAG_NOCONFLICTS = 0x800, PM_TRANS_FLAG_PRINTURIS = 0x1000, - PM_TRANS_FLAG_NEEDED = 0x2000 + PM_TRANS_FLAG_NEEDED = 0x2000, + PM_TRANS_FLAG_ALLEXPLICIT = 0x4000, + PM_TRANS_FLAG_UNNEEDED = 0x8000, + PM_TRANS_FLAG_RECURSEALL = 0x10000 } pmtransflag_t; -/* Transaction Events */ +/** + * @addtogroup alpm_trans + * @{ + */ +/** + * @brief Transaction events. + * NULL parameters are passed to in all events unless specified otherwise. + */ typedef enum _pmtransevt_t { + /** Dependencies will be computed for a package. */ PM_TRANS_EVT_CHECKDEPS_START = 1, + /** Dependencies were computed for a package. */ PM_TRANS_EVT_CHECKDEPS_DONE, + /** File conflicts will be computed for a package. */ PM_TRANS_EVT_FILECONFLICTS_START, + /** File conflicts were computed for a package. */ PM_TRANS_EVT_FILECONFLICTS_DONE, + /** Dependencies will be resolved for target package. */ PM_TRANS_EVT_RESOLVEDEPS_START, + /** Dependencies were resolved for target package. */ PM_TRANS_EVT_RESOLVEDEPS_DONE, + /** Inter-conflicts will be checked for target package. */ PM_TRANS_EVT_INTERCONFLICTS_START, + /** Inter-conflicts were checked for target package. */ PM_TRANS_EVT_INTERCONFLICTS_DONE, + /** Package will be installed. + * A pointer to the target package is passed to the callback. + */ PM_TRANS_EVT_ADD_START, + /** Package was installed. + * A pointer to the new package is passed to the callback. + */ PM_TRANS_EVT_ADD_DONE, + /** Package will be removed. + * A pointer to the target package is passed to the callback. + */ PM_TRANS_EVT_REMOVE_START, + /** Package was removed. + * A pointer to the removed package is passed to the callback. + */ PM_TRANS_EVT_REMOVE_DONE, + /** Package will be upgraded. + * A pointer to the upgraded package is passed to the callback. + */ PM_TRANS_EVT_UPGRADE_START, + /** Package was upgraded. + * A pointer to the new package, and a pointer to the old package is passed + * to the callback, respectively. + */ PM_TRANS_EVT_UPGRADE_DONE, - PM_TRANS_EVT_EXTRACT_DONE, + /** Target package's integrity will be checked. */ PM_TRANS_EVT_INTEGRITY_START, + /** Target package's integrity was checked. */ PM_TRANS_EVT_INTEGRITY_DONE, + /** Target deltas's integrity will be checked. */ PM_TRANS_EVT_DELTA_INTEGRITY_START, + /** Target delta's integrity was checked. */ PM_TRANS_EVT_DELTA_INTEGRITY_DONE, + /** Deltas will be applied to packages. */ PM_TRANS_EVT_DELTA_PATCHES_START, + /** Deltas were applied to packages. */ PM_TRANS_EVT_DELTA_PATCHES_DONE, + /** Delta patch will be applied to target package. + * The filename of the package and the filename of the patch is passed to the + * callback. + */ PM_TRANS_EVT_DELTA_PATCH_START, + /** Delta patch was applied to target package. */ PM_TRANS_EVT_DELTA_PATCH_DONE, + /** Delta patch failed to apply to target package. */ PM_TRANS_EVT_DELTA_PATCH_FAILED, + /** Scriptlet has printed information. + * A line of text is passed to the callback. + */ PM_TRANS_EVT_SCRIPTLET_INFO, + /** Print URI. + * The database's URI and the package's filename are passed to the callback. + */ PM_TRANS_EVT_PRINTURI, + /** Files will be downloaded from a repository. + * The repository's tree name is passed to the callback. + */ PM_TRANS_EVT_RETRIEVE_START, } pmtransevt_t; +/*@}*/ /* Transaction Conversations (ie, questions) */ typedef enum _pmtransconv_t { @@ -353,7 +401,6 @@ typedef void (*alpm_trans_cb_progress)(pmtransprog_t, const char *, int, int, in pmtranstype_t alpm_trans_get_type(); unsigned int alpm_trans_get_flags(); -alpm_list_t * alpm_trans_get_targets(); alpm_list_t * alpm_trans_get_pkgs(); int alpm_trans_init(pmtranstype_t type, pmtransflag_t flags, alpm_trans_cb_event cb_event, alpm_trans_cb_conv conv, @@ -378,13 +425,17 @@ typedef enum _pmdepmod_t { PM_DEP_MOD_LT } pmdepmod_t; -pmdepend_t *alpm_splitdep(const char *depstring); int alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep); alpm_list_t *alpm_checkdeps(pmdb_t *db, int reversedeps, alpm_list_t *remove, alpm_list_t *upgrade); +alpm_list_t *alpm_deptest(pmdb_t *db, alpm_list_t *targets); +alpm_list_t *alpm_find_pkg_satisfiers(alpm_list_t *pkgs, const char *pkgname); const char *alpm_miss_get_target(const pmdepmissing_t *miss); pmdepend_t *alpm_miss_get_dep(pmdepmissing_t *miss); +const char *alpm_miss_get_causingpkg(const pmdepmissing_t *miss); + +alpm_list_t *alpm_checkdbconflicts(pmdb_t *db_local); const char *alpm_conflict_get_package1(pmconflict_t *conflict); const char *alpm_conflict_get_package2(pmconflict_t *conflict); @@ -439,12 +490,6 @@ enum _pmerrno_t { PM_ERR_DB_REMOVE, /* Servers */ PM_ERR_SERVER_BAD_URL, - /* Configuration */ - PM_ERR_OPT_LOGFILE, - PM_ERR_OPT_DBPATH, - PM_ERR_OPT_LOCALDB, - PM_ERR_OPT_SYNCDB, - PM_ERR_OPT_USESYSLOG, /* Transactions */ PM_ERR_TRANS_NOT_NULL, PM_ERR_TRANS_NULL, @@ -460,14 +505,12 @@ enum _pmerrno_t { PM_ERR_PKG_INVALID, PM_ERR_PKG_OPEN, PM_ERR_PKG_LOAD, - PM_ERR_PKG_INSTALLED, PM_ERR_PKG_CANT_FRESH, PM_ERR_PKG_CANT_REMOVE, PM_ERR_PKG_INVALID_NAME, - PM_ERR_PKG_CORRUPTED, PM_ERR_PKG_REPO_NOT_FOUND, /* Deltas */ - PM_ERR_DLT_CORRUPTED, + PM_ERR_DLT_INVALID, PM_ERR_DLT_PATCHFAILED, /* Groups */ PM_ERR_GRP_NOT_FOUND, @@ -478,14 +521,14 @@ enum _pmerrno_t { /* Misc */ PM_ERR_USER_ABORT, PM_ERR_INTERNAL_ERROR, - PM_ERR_LIBARCHIVE_ERROR, PM_ERR_DB_SYNC, PM_ERR_RETRIEVE, PM_ERR_PKG_HOLD, PM_ERR_INVALID_REGEX, - /* Downloading */ - PM_ERR_CONNECT_FAILED, - PM_ERR_FORK_FAILED + /* External library errors */ + PM_ERR_LIBARCHIVE, + PM_ERR_LIBDOWNLOAD, + PM_ERR_EXTERNAL_DOWNLOAD }; extern enum _pmerrno_t pm_errno; diff --git a/lib/libalpm/alpm_list.c b/lib/libalpm/alpm_list.c index 57c8376a..87567402 100644 --- a/lib/libalpm/alpm_list.c +++ b/lib/libalpm/alpm_list.c @@ -1,7 +1,7 @@ /* * alpm_list.c * - * Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org> + * Copyright (c) 2002-2008 by Judd Vinet <jvinet@zeroflux.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 @@ -17,15 +17,16 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <string.h> #include <stdio.h> /* libalpm */ #include "alpm_list.h" -#include "util.h" + +/* check exported library symbols with: nm -C -D <lib> */ +#define SYMEXPORT __attribute__((visibility("default"))) +#define SYMHIDDEN __attribute__((visibility("internal"))) /** * @addtogroup alpm_list List Functions @@ -40,25 +41,6 @@ /* Allocation */ /** - * @brief Allocate a new alpm_list_t. - * - * @return a new alpm_list_t item, or NULL on failure - */ -alpm_list_t SYMEXPORT *alpm_list_new() -{ - alpm_list_t *list = NULL; - - list = malloc(sizeof(alpm_list_t)); - if(list) { - list->data = NULL; - list->prev = list; /* maintain a back reference to the tail pointer */ - list->next = NULL; - } - - return(list); -} - -/** * @brief Free a list, but not the contained data. * * @param list the list to free @@ -107,30 +89,26 @@ alpm_list_t SYMEXPORT *alpm_list_add(alpm_list_t *list, void *data) { alpm_list_t *ptr, *lp; - ptr = list; + ptr = calloc(1, sizeof(alpm_list_t)); if(ptr == NULL) { - ptr = alpm_list_new(); - if(ptr == NULL) { - return(NULL); - } + return(list); } - lp = alpm_list_last(ptr); - if(lp == ptr && lp->data == NULL) { - /* nada */ - } else { - lp->next = alpm_list_new(); - if(lp->next == NULL) { - return(NULL); - } - lp->next->prev = lp; - lp = lp->next; - list->prev = lp; + ptr->data = data; + ptr->next = NULL; + + /* Special case: the input list is empty */ + if(list == NULL) { + ptr->prev = ptr; + return(ptr); } - lp->data = data; + lp = alpm_list_last(list); + lp->next = ptr; + ptr->prev = lp; + list->prev = ptr; - return(ptr); + return(list); } /** @@ -144,12 +122,15 @@ alpm_list_t SYMEXPORT *alpm_list_add(alpm_list_t *list, void *data) */ alpm_list_t SYMEXPORT *alpm_list_add_sorted(alpm_list_t *list, void *data, alpm_list_fn_cmp fn) { - if(!fn) { - return alpm_list_add(list, data); + if(!fn || !list) { + return(alpm_list_add(list, data)); } else { alpm_list_t *add = NULL, *prev = NULL, *next = list; - add = alpm_list_new(); + add = calloc(1, sizeof(alpm_list_t)); + if(add == NULL) { + return(list); + } add->data = data; /* Find insertion point. */ @@ -159,26 +140,25 @@ alpm_list_t SYMEXPORT *alpm_list_add_sorted(alpm_list_t *list, void *data, alpm_ next = next->next; } - /* Insert node before insertion point. */ - add->prev = prev; - add->next = next; - - if(next != NULL) { - next->prev = add; /* Not at end. */ - } - - if(prev != NULL) { - prev->next = add; /* In middle. */ - } else { - list = add; /* At beginning, or new list */ - } - - if(next == NULL) { - /* At end, adjust tail pointer on head node */ + /* Insert the add node to the list */ + if(prev == NULL) { /* special case: we insert add as the first element */ + add->prev = list->prev; /* list != NULL */ + add->next = list; list->prev = add; + return(add); + } else if(next == NULL) { /* another special case: add last element */ + add->prev = prev; + add->next = NULL; + prev->next = add; + list->prev = add; + return(list); + } else { + add->prev = prev; + add->next = next; + next->prev = add; + prev->next = add; + return(list); } - - return(list); } } @@ -198,10 +178,10 @@ alpm_list_t SYMEXPORT *alpm_list_join(alpm_list_t *first, alpm_list_t *second) alpm_list_t *tmp; if (first == NULL) { - return second; + return(second); } if (second == NULL) { - return first; + return(first); } /* tmp is the last element of the first list */ tmp = first->prev; @@ -327,7 +307,7 @@ alpm_list_t SYMEXPORT *alpm_list_remove(alpm_list_t *haystack, const void *needl continue; } tmp = i->next; - if(fn(needle, i->data) == 0) { + if(fn(i->data, needle) == 0) { /* we found a matching item */ if(i == haystack) { /* Special case: removing the head node which has a back reference to @@ -371,6 +351,22 @@ alpm_list_t SYMEXPORT *alpm_list_remove(alpm_list_t *haystack, const void *needl } /** + * @brief Remove a string from a list. + * + * @param haystack the list to remove the item from + * @param needle the data member of the item we're removing + * @param data output parameter containing data of the removed item + * + * @return the resultant list + */ +alpm_list_t SYMEXPORT *alpm_list_remove_str(alpm_list_t *haystack, + const char *needle, char **data) +{ + return(alpm_list_remove(haystack, (const void *)needle, + (alpm_list_fn_cmp)strcmp, (void **)data)); +} + +/** * @brief Create a new list without any duplicates. * * This does NOT copy data members. @@ -464,18 +460,22 @@ alpm_list_t SYMEXPORT *alpm_list_copy_data(const alpm_list_t *list, alpm_list_t SYMEXPORT *alpm_list_reverse(alpm_list_t *list) { const alpm_list_t *lp; - alpm_list_t *newlist = NULL; + alpm_list_t *newlist = NULL, *backup; - lp = alpm_list_last(list); - if(list) { - /* break our reverse circular list */ - list->prev = NULL; + if(list == NULL) { + return(NULL); } + lp = alpm_list_last(list); + /* break our reverse circular list */ + backup = list->prev; + list->prev = NULL; + while(lp) { newlist = alpm_list_add(newlist, lp->data); lp = lp->prev; } + list->prev = backup; /* restore tail pointer */ return(newlist); } @@ -490,14 +490,18 @@ alpm_list_t SYMEXPORT *alpm_list_reverse(alpm_list_t *list) */ inline alpm_list_t SYMEXPORT *alpm_list_first(const alpm_list_t *list) { - return((alpm_list_t*)list); + if(list) { + return((alpm_list_t*)list); + } else { + return(NULL); + } } /** * @brief Return nth element from list (starting from 0). * * @param list the list - * @param n the index of the item to find + * @param n the index of the item to find (n < alpm_list_count(list) IS needed) * * @return an alpm_list_t node for index `n` */ @@ -519,7 +523,11 @@ alpm_list_t SYMEXPORT *alpm_list_nth(const alpm_list_t *list, int n) */ inline alpm_list_t SYMEXPORT *alpm_list_next(const alpm_list_t *node) { - return(node->next); + if(node) { + return(node->next); + } else { + return(NULL); + } } /** @@ -594,7 +602,7 @@ void SYMEXPORT *alpm_list_find(const alpm_list_t *haystack, const void *needle, } /* trivial helper function for alpm_list_find_ptr */ -static int ptrcmp(const void *p, const void *q) +static int ptr_cmp(const void *p, const void *q) { return(p != q); } @@ -611,7 +619,7 @@ static int ptrcmp(const void *p, const void *q) */ void SYMEXPORT *alpm_list_find_ptr(const alpm_list_t *haystack, const void *needle) { - return(alpm_list_find(haystack, needle, ptrcmp)); + return(alpm_list_find(haystack, needle, ptr_cmp)); } /** @@ -622,9 +630,11 @@ void SYMEXPORT *alpm_list_find_ptr(const alpm_list_t *haystack, const void *need * * @return `needle` if found, NULL otherwise */ -char SYMEXPORT *alpm_list_find_str(const alpm_list_t *haystack, const char *needle) +char SYMEXPORT *alpm_list_find_str(const alpm_list_t *haystack, + const char *needle) { - return((char *)alpm_list_find(haystack, (const void*)needle, (alpm_list_fn_cmp)strcmp)); + return((char *)alpm_list_find(haystack, (const void*)needle, + (alpm_list_fn_cmp)strcmp)); } /** diff --git a/lib/libalpm/alpm_list.h b/lib/libalpm/alpm_list.h index ae373910..8dc8c5ff 100644 --- a/lib/libalpm/alpm_list.h +++ b/lib/libalpm/alpm_list.h @@ -19,6 +19,8 @@ #ifndef _ALPM_LIST_H #define _ALPM_LIST_H +#include <stdlib.h> /* size_t */ + #ifdef __cplusplus extern "C" { #endif @@ -45,7 +47,6 @@ typedef void (*alpm_list_fn_free)(void *); /* item deallocation callback */ typedef int (*alpm_list_fn_cmp)(const void *, const void *); /* item comparison callback */ /* allocation */ -alpm_list_t *alpm_list_new(void); void alpm_list_free(alpm_list_t *list); void alpm_list_free_inner(alpm_list_t *list, alpm_list_fn_free fn); @@ -56,6 +57,7 @@ alpm_list_t *alpm_list_join(alpm_list_t *first, alpm_list_t *second); alpm_list_t *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right, alpm_list_fn_cmp fn); alpm_list_t *alpm_list_msort(alpm_list_t *list, int n, alpm_list_fn_cmp fn); alpm_list_t *alpm_list_remove(alpm_list_t *haystack, const void *needle, alpm_list_fn_cmp fn, void **data); +alpm_list_t *alpm_list_remove_str(alpm_list_t *haystack, const char *needle, char **data); alpm_list_t *alpm_list_remove_dupes(const alpm_list_t *list); alpm_list_t *alpm_list_strdup(const alpm_list_t *list); alpm_list_t *alpm_list_copy(const alpm_list_t *list); diff --git a/lib/libalpm/be_files.c b/lib/libalpm/be_files.c index 4cd0985e..2302374d 100644 --- a/lib/libalpm/be_files.c +++ b/lib/libalpm/be_files.c @@ -36,32 +36,171 @@ /* libalpm */ #include "db.h" #include "alpm_list.h" +#include "cache.h" #include "log.h" #include "util.h" #include "alpm.h" -#include "error.h" #include "handle.h" #include "package.h" #include "delta.h" #include "deps.h" +#include "dload.h" -/* This function is used to convert the downloaded db file to the proper backend - * format +/* + * Return the last update time as number of seconds from the epoch. + * Returns 0 if the value is unknown or can't be read. */ -int _alpm_db_install(pmdb_t *db, const char *dbfile) +time_t getlastupdate(const pmdb_t *db) { + FILE *fp; + char *file; + time_t ret = 0; + ALPM_LOG_FUNC; - /* TODO we should not simply unpack the archive, but better parse it and - * db_write each entry (see sync_load_dbarchive to get archive content) */ - _alpm_log(PM_LOG_DEBUG, "unpacking database '%s'\n", dbfile); + if(db == NULL) { + return(ret); + } + + /* db->path + '.lastupdate' + NULL */ + MALLOC(file, strlen(db->path) + 12, RET_ERR(PM_ERR_MEMORY, ret)); + sprintf(file, "%s.lastupdate", db->path); + + /* get the last update time, if it's there */ + if((fp = fopen(file, "r")) == NULL) { + free(file); + return(ret); + } else { + char line[64]; + if(fgets(line, sizeof(line), fp)) { + ret = atol(line); + } + } + fclose(fp); + free(file); + return(ret); +} + +/* + * writes the dbpath/.lastupdate file with the value in time + */ +int setlastupdate(const pmdb_t *db, time_t time) +{ + FILE *fp; + char *file; + int ret = 0; + + ALPM_LOG_FUNC; - if(_alpm_unpack(dbfile, db->path, NULL)) { - RET_ERR(PM_ERR_SYSTEM, -1); + if(db == NULL || time == 0) { + return(-1); } - return unlink(dbfile); + /* db->path + '.lastupdate' + NULL */ + MALLOC(file, strlen(db->path) + 12, RET_ERR(PM_ERR_MEMORY, ret)); + sprintf(file, "%s.lastupdate", db->path); + + if((fp = fopen(file, "w")) == NULL) { + free(file); + return(-1); + } + if(fprintf(fp, "%ju", (uintmax_t)time) <= 0) { + ret = -1; + } + fclose(fp); + free(file); + return(ret); +} + +/** Update a package database + * @param force if true, then forces the update, otherwise update only in case + * the database isn't up to date + * @param db pointer to the package database to update + * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up + * to date + */ +int SYMEXPORT alpm_db_update(int force, pmdb_t *db) +{ + alpm_list_t *lp; + char path[PATH_MAX]; + time_t newmtime = 0, lastupdate = 0; + const char *dbpath; + int ret; + + ALPM_LOG_FUNC; + + /* Sanity checks */ + ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1)); + ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1)); + /* Verify we are in a transaction. This is done _mainly_ because we need a DB + * lock - if we update without a db lock, we may kludge some other pacman + * process that _has_ a lock. + */ + ASSERT(handle->trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1)); + ASSERT(handle->trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1)); + ASSERT(handle->trans->type == PM_TRANS_TYPE_SYNC, RET_ERR(PM_ERR_TRANS_TYPE, -1)); + + if(!alpm_list_find_ptr(handle->dbs_sync, db)) { + RET_ERR(PM_ERR_DB_NOT_FOUND, -1); + } + + if(!force) { + /* get the lastupdate time */ + lastupdate = getlastupdate(db); + if(lastupdate == 0) { + _alpm_log(PM_LOG_DEBUG, "failed to get lastupdate time for %s\n", + db->treename); + } + } + + snprintf(path, PATH_MAX, "%s" DBEXT, db->treename); + dbpath = alpm_option_get_dbpath(); + + ret = _alpm_download_single_file(path, db->servers, dbpath, + lastupdate, &newmtime); + + if(ret == 1) { + /* mtimes match, do nothing */ + pm_errno = 0; + return(1); + } else if(ret == -1) { + /* pm_errno was set by the download code */ + _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast()); + return(-1); + } else { + /* form the path to the db location */ + snprintf(path, PATH_MAX, "%s%s" DBEXT, dbpath, db->treename); + + /* remove the old dir */ + _alpm_log(PM_LOG_DEBUG, "flushing database %s\n", db->path); + for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) { + pmpkg_t *pkg = lp->data; + if(pkg && _alpm_db_remove(db, pkg) == -1) { + _alpm_log(PM_LOG_ERROR, _("could not remove database entry %s%s\n"), + db->treename, pkg->name); + RET_ERR(PM_ERR_DB_REMOVE, -1); + } + } + + /* Cache needs to be rebuilt */ + _alpm_db_free_pkgcache(db); + + /* uncompress the sync database */ + if(_alpm_unpack(path, db->path, NULL)) { + RET_ERR(PM_ERR_SYSTEM, -1); + } + unlink(path); + + /* if we have a new mtime, set the DB last update value */ + if(newmtime) { + _alpm_log(PM_LOG_DEBUG, "sync: new mtime for %s: %ju\n", + db->treename, (uintmax_t)newmtime); + setlastupdate(db, newmtime); + } + } + + return(0); } int _alpm_db_open(pmdb_t *db) @@ -95,18 +234,7 @@ void _alpm_db_close(pmdb_t *db) } } -void _alpm_db_rewind(pmdb_t *db) -{ - ALPM_LOG_FUNC; - - if(db == NULL || db->handle == NULL) { - return; - } - - rewinddir(db->handle); -} - -static int _alpm_db_splitname(const char *target, char *name, char *version) +static int splitname(const char *target, pmpkg_t *pkg) { /* the format of a db entry is as follows: * package-version-rel/ @@ -115,10 +243,10 @@ static int _alpm_db_splitname(const char *target, char *name, char *version) */ char *tmp, *p, *q; - if(target == NULL) { + if(target == NULL || pkg == NULL) { return(-1); } - tmp = strdup(target); + STRDUP(tmp, target, RET_ERR(PM_ERR_MEMORY, -1)); p = tmp + strlen(tmp); /* do the magic parsing- find the beginning of the version string @@ -130,119 +258,82 @@ static int _alpm_db_splitname(const char *target, char *name, char *version) } /* copy into fields and return */ - if(version) { - strncpy(version, p+1, PKG_VERSION_LEN); + if(pkg->version) { + FREE(pkg->version); } + STRDUP(pkg->version, p+1, RET_ERR(PM_ERR_MEMORY, -1)); /* insert a terminator at the end of the name (on hyphen)- then copy it */ *p = '\0'; - if(name) { - strncpy(name, tmp, PKG_NAME_LEN); + if(pkg->name) { + FREE(pkg->name); } + STRDUP(pkg->name, tmp, RET_ERR(PM_ERR_MEMORY, -1)); free(tmp); return(0); } -pmpkg_t *_alpm_db_scan(pmdb_t *db, const char *target) +int _alpm_db_populate(pmdb_t *db) { + int count = 0; struct dirent *ent = NULL; struct stat sbuf; char path[PATH_MAX]; - char name[PKG_FULLNAME_LEN]; - char *ptr = NULL; - int found = 0; - pmpkg_t *pkg = NULL; ALPM_LOG_FUNC; - if(db == NULL) { - RET_ERR(PM_ERR_DB_NULL, NULL); - } + ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1)); - /* We loop here until we read a valid package. When an iteration of this loop - * fails, it means alpm_db_read failed to read a valid package, so we'll read - * the next so as not to abort whole-db operations early - */ - while(!pkg) { - if(target != NULL) { - /* search for a specific package (by name only) */ - rewinddir(db->handle); - while(!found && (ent = readdir(db->handle)) != NULL) { - if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) { - continue; - } - /* stat the entry, make sure it's a directory */ - snprintf(path, PATH_MAX, "%s/%s", db->path, ent->d_name); - if(stat(path, &sbuf) || !S_ISDIR(sbuf.st_mode)) { - continue; - } - strncpy(name, ent->d_name, PKG_FULLNAME_LEN); - /* truncate the string at the second-to-last hyphen, */ - /* which will give us the package name */ - if((ptr = rindex(name, '-'))) { - *ptr = '\0'; - } - if((ptr = rindex(name, '-'))) { - *ptr = '\0'; - } - if(!strcmp(name, target)) { - found = 1; - } - } - if(!found) { - return(NULL); - } - } else { /* target == NULL, full scan */ - int isdir = 0; - while(!isdir) { - ent = readdir(db->handle); - if(ent == NULL) { - return(NULL); - } - if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) { - isdir = 0; - continue; - } - /* stat the entry, make sure it's a directory */ - snprintf(path, PATH_MAX, "%s/%s", db->path, ent->d_name); - if(!stat(path, &sbuf) && S_ISDIR(sbuf.st_mode)) { - isdir = 1; - } - } + rewinddir(db->handle); + while((ent = readdir(db->handle)) != NULL) { + const char *name = ent->d_name; + pmpkg_t *pkg; + + if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { + continue; + } + /* stat the entry, make sure it's a directory */ + snprintf(path, PATH_MAX, "%s/%s", db->path, name); + if(stat(path, &sbuf) != 0 || !S_ISDIR(sbuf.st_mode)) { + continue; } - pkg = _alpm_pkg_new(NULL, NULL); + pkg = _alpm_pkg_new(); if(pkg == NULL) { - _alpm_log(PM_LOG_DEBUG, "db scan could not find package: %s\n", target); - return(NULL); + return(-1); } /* split the db entry name */ - if(_alpm_db_splitname(ent->d_name, pkg->name, pkg->version) != 0) { + if(splitname(name, pkg) != 0) { _alpm_log(PM_LOG_ERROR, _("invalid name for database entry '%s'\n"), - ent->d_name); - alpm_pkg_free(pkg); - pkg = NULL; + name); + _alpm_pkg_free(pkg); continue; } /* explicitly read with only 'BASE' data, accessors will handle the rest */ if(_alpm_db_read(db, pkg, INFRQ_BASE) == -1) { - /* TODO removed corrupt entry from the FS here */ + _alpm_log(PM_LOG_ERROR, _("corrupted database entry '%s'\n"), name); _alpm_pkg_free(pkg); - } else { - pkg->origin = PKG_FROM_CACHE; - pkg->origin_data.db = db; + continue; } + pkg->origin = PKG_FROM_CACHE; + pkg->origin_data.db = db; + /* add to the collection */ + _alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n", + pkg->name, db->treename); + db->pkgcache = alpm_list_add(db->pkgcache, pkg); + count++; } - return(pkg); + db->pkgcache = alpm_list_msort(db->pkgcache, count, _alpm_pkg_cmp); + return(count); } int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) { FILE *fp = NULL; struct stat buf; - char path[PATH_MAX+1]; + char path[PATH_MAX]; char line[513]; ALPM_LOG_FUNC; @@ -251,7 +342,7 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) RET_ERR(PM_ERR_DB_NULL, -1); } - if(info == NULL || info->name[0] == 0 || info->version[0] == 0) { + if(info == NULL || info->name == NULL || info->version == NULL) { _alpm_log(PM_LOG_DEBUG, "invalid package entry provided to _alpm_db_read, skipping\n"); return(-1); } @@ -296,120 +387,131 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) break; } _alpm_strtrim(line); - if(!strcmp(line, "%FILENAME%")) { - if(fgets(info->filename, sizeof(info->filename), fp) == NULL) { + if(strcmp(line, "%NAME%") == 0) { + if(fgets(line, 512, fp) == NULL) { + goto error; + } + if(strcmp(_alpm_strtrim(line), info->name) != 0) { + _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: name " + "mismatch on package %s\n"), db->treename, info->name); + } + } else if(strcmp(line, "%VERSION%") == 0) { + if(fgets(line, 512, fp) == NULL) { goto error; } - _alpm_strtrim(info->filename); - } else if(!strcmp(line, "%DESC%")) { - if(fgets(info->desc, sizeof(info->desc), fp) == NULL) { + if(strcmp(_alpm_strtrim(line), info->version) != 0) { + _alpm_log(PM_LOG_ERROR, _("%s database is inconsistent: version " + "mismatch on package %s\n"), db->treename, info->name); + } + } else if(strcmp(line, "%FILENAME%") == 0) { + if(fgets(line, 512, fp) == NULL) { goto error; } - _alpm_strtrim(info->desc); - } else if(!strcmp(line, "%GROUPS%")) { + STRDUP(info->filename, _alpm_strtrim(line), goto error); + } else if(strcmp(line, "%DESC%") == 0) { + if(fgets(line, 512, fp) == NULL) { + goto error; + } + STRDUP(info->desc, _alpm_strtrim(line), goto error); + } else if(strcmp(line, "%GROUPS%") == 0) { while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) { - info->groups = alpm_list_add(info->groups, strdup(line)); + char *linedup; + STRDUP(linedup, _alpm_strtrim(line), goto error); + info->groups = alpm_list_add(info->groups, linedup); } - } else if(!strcmp(line, "%URL%")) { - if(fgets(info->url, sizeof(info->url), fp) == NULL) { + } else if(strcmp(line, "%URL%") == 0) { + if(fgets(line, 512, fp) == NULL) { goto error; } - _alpm_strtrim(info->url); - } else if(!strcmp(line, "%LICENSE%")) { + STRDUP(info->url, _alpm_strtrim(line), goto error); + } else if(strcmp(line, "%LICENSE%") == 0) { while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) { - info->licenses = alpm_list_add(info->licenses, strdup(line)); + char *linedup; + STRDUP(linedup, _alpm_strtrim(line), goto error); + info->licenses = alpm_list_add(info->licenses, linedup); } - } else if(!strcmp(line, "%ARCH%")) { - if(fgets(info->arch, sizeof(info->arch), fp) == NULL) { + } else if(strcmp(line, "%ARCH%") == 0) { + if(fgets(line, 512, fp) == NULL) { goto error; } - _alpm_strtrim(info->arch); - } else if(!strcmp(line, "%BUILDDATE%")) { - char tmp[32]; - if(fgets(tmp, sizeof(tmp), fp) == NULL) { + STRDUP(info->arch, _alpm_strtrim(line), goto error); + } else if(strcmp(line, "%BUILDDATE%") == 0) { + if(fgets(line, 512, fp) == NULL) { goto error; } - _alpm_strtrim(tmp); + _alpm_strtrim(line); - char first = tolower(tmp[0]); + char first = tolower(line[0]); if(first > 'a' && first < 'z') { struct tm tmp_tm = {0}; //initialize to null incase of failure setlocale(LC_TIME, "C"); - strptime(tmp, "%a %b %e %H:%M:%S %Y", &tmp_tm); + strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm); info->builddate = mktime(&tmp_tm); setlocale(LC_TIME, ""); } else { - info->builddate = atol(tmp); + info->builddate = atol(line); } - } else if(!strcmp(line, "%INSTALLDATE%")) { - char tmp[32]; - if(fgets(tmp, sizeof(tmp), fp) == NULL) { + } else if(strcmp(line, "%INSTALLDATE%") == 0) { + if(fgets(line, 512, fp) == NULL) { goto error; } - _alpm_strtrim(tmp); + _alpm_strtrim(line); - char first = tolower(tmp[0]); + char first = tolower(line[0]); if(first > 'a' && first < 'z') { struct tm tmp_tm = {0}; //initialize to null incase of failure setlocale(LC_TIME, "C"); - strptime(tmp, "%a %b %e %H:%M:%S %Y", &tmp_tm); + strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm); info->installdate = mktime(&tmp_tm); setlocale(LC_TIME, ""); } else { - info->installdate = atol(tmp); + info->installdate = atol(line); } - } else if(!strcmp(line, "%PACKAGER%")) { - if(fgets(info->packager, sizeof(info->packager), fp) == NULL) { + } else if(strcmp(line, "%PACKAGER%") == 0) { + if(fgets(line, 512, fp) == NULL) { goto error; } - _alpm_strtrim(info->packager); - } else if(!strcmp(line, "%REASON%")) { - char tmp[32]; - if(fgets(tmp, sizeof(tmp), fp) == NULL) { + STRDUP(info->packager, _alpm_strtrim(line), goto error); + } else if(strcmp(line, "%REASON%") == 0) { + if(fgets(line, 512, fp) == NULL) { goto error; } - _alpm_strtrim(tmp); - info->reason = atol(tmp); - } else if(!strcmp(line, "%SIZE%") || !strcmp(line, "%CSIZE%")) { + info->reason = atol(_alpm_strtrim(line)); + } else if(strcmp(line, "%SIZE%") == 0 || strcmp(line, "%CSIZE%") == 0) { /* NOTE: the CSIZE and SIZE fields both share the "size" field * in the pkginfo_t struct. This can be done b/c CSIZE * is currently only used in sync databases, and SIZE is * only used in local databases. */ - char tmp[32]; - if(fgets(tmp, sizeof(tmp), fp) == NULL) { + if(fgets(line, 512, fp) == NULL) { goto error; } - _alpm_strtrim(tmp); - info->size = atol(tmp); + info->size = atol(_alpm_strtrim(line)); /* also store this value to isize if isize is unset */ if(info->isize == 0) { - info->isize = atol(tmp); + info->isize = info->size; } - } else if(!strcmp(line, "%ISIZE%")) { + } else if(strcmp(line, "%ISIZE%") == 0) { /* ISIZE (installed size) tag only appears in sync repositories, * not the local one. */ - char tmp[32]; - if(fgets(tmp, sizeof(tmp), fp) == NULL) { + if(fgets(line, 512, fp) == NULL) { goto error; } - _alpm_strtrim(tmp); - info->isize = atol(tmp); - } else if(!strcmp(line, "%MD5SUM%")) { + info->isize = atol(_alpm_strtrim(line)); + } else if(strcmp(line, "%MD5SUM%") == 0) { /* MD5SUM tag only appears in sync repositories, * not the local one. */ - if(fgets(info->md5sum, sizeof(info->md5sum), fp) == NULL) { + if(fgets(line, 512, fp) == NULL) { goto error; } - } else if(!strcmp(line, "%REPLACES%")) { - /* the REPLACES tag is special -- it only appears in sync repositories, - * not the local one. */ + STRDUP(info->md5sum, _alpm_strtrim(line), goto error); + } else if(strcmp(line, "%REPLACES%") == 0) { while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) { - info->replaces = alpm_list_add(info->replaces, strdup(line)); + char *linedup; + STRDUP(linedup, _alpm_strtrim(line), goto error); + info->replaces = alpm_list_add(info->replaces, linedup); } - } else if(!strcmp(line, "%FORCE%")) { - /* FORCE tag only appears in sync repositories, - * not the local one. */ + } else if(strcmp(line, "%FORCE%") == 0) { info->force = 1; } } @@ -426,13 +528,17 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) } while(fgets(line, 256, fp)) { _alpm_strtrim(line); - if(!strcmp(line, "%FILES%")) { + if(strcmp(line, "%FILES%") == 0) { while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) { - info->files = alpm_list_add(info->files, strdup(line)); + char *linedup; + STRDUP(linedup, _alpm_strtrim(line), goto error); + info->files = alpm_list_add(info->files, linedup); } - } else if(!strcmp(line, "%BACKUP%")) { + } else if(strcmp(line, "%BACKUP%") == 0) { while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) { - info->backup = alpm_list_add(info->backup, strdup(line)); + char *linedup; + STRDUP(linedup, _alpm_strtrim(line), goto error); + info->backup = alpm_list_add(info->backup, linedup); } } } @@ -450,37 +556,30 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) while(!feof(fp)) { fgets(line, 255, fp); _alpm_strtrim(line); - if(!strcmp(line, "%DEPENDS%")) { + if(strcmp(line, "%DEPENDS%") == 0) { while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) { - pmdepend_t *dep = alpm_splitdep(line); + pmdepend_t *dep = _alpm_splitdep(_alpm_strtrim(line)); info->depends = alpm_list_add(info->depends, dep); } - } else if(!strcmp(line, "%OPTDEPENDS%")) { + } else if(strcmp(line, "%OPTDEPENDS%") == 0) { while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) { - info->optdepends = alpm_list_add(info->optdepends, strdup(line)); + char *linedup; + STRDUP(linedup, _alpm_strtrim(line), goto error); + info->optdepends = alpm_list_add(info->optdepends, linedup); } - } else if(!strcmp(line, "%CONFLICTS%")) { + } else if(strcmp(line, "%CONFLICTS%") == 0) { while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) { - info->conflicts = alpm_list_add(info->conflicts, strdup(line)); + char *linedup; + STRDUP(linedup, _alpm_strtrim(line), goto error); + info->conflicts = alpm_list_add(info->conflicts, linedup); } - } else if(!strcmp(line, "%PROVIDES%")) { + } else if(strcmp(line, "%PROVIDES%") == 0) { while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) { - info->provides = alpm_list_add(info->provides, strdup(line)); + char *linedup; + STRDUP(linedup, _alpm_strtrim(line), goto error); + info->provides = alpm_list_add(info->provides, linedup); } } - /* TODO: we were going to move these things here, but it should wait. - * A better change would be to figure out how to restructure the DB. */ - /* else if(!strcmp(line, "%REPLACES%")) { - * the REPLACES tag is special -- it only appears in sync repositories, - * not the local one. * - while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) { - info->replaces = alpm_list_add(info->replaces, strdup(line)); - } - } else if(!strcmp(line, "%FORCE%")) { - * FORCE tag only appears in sync repositories, - * not the local one. * - info->force = 1; - } */ } fclose(fp); fp = NULL; @@ -488,12 +587,13 @@ int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) /* DELTAS */ if(inforeq & INFRQ_DELTAS) { - snprintf(path, PATH_MAX, "%s/%s-%s/deltas", db->path, info->name, info->version); + snprintf(path, PATH_MAX, "%s/%s-%s/deltas", db->path, + info->name, info->version); if((fp = fopen(path, "r"))) { while(!feof(fp)) { fgets(line, 255, fp); _alpm_strtrim(line); - if(!strcmp(line, "%DELTAS%")) { + if(strcmp(line, "%DELTAS%") == 0) { while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) { info->deltas = alpm_list_add(info->deltas, _alpm_delta_parse(line)); } @@ -561,7 +661,7 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) } fprintf(fp, "%%NAME%%\n%s\n\n" "%%VERSION%%\n%s\n\n", info->name, info->version); - if(info->desc[0]) { + if(info->desc) { fprintf(fp, "%%DESC%%\n" "%s\n\n", info->desc); } @@ -572,8 +672,18 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) } fprintf(fp, "\n"); } + if(info->replaces) { + fputs("%REPLACES%\n", fp); + for(lp = info->replaces; lp; lp = lp->next) { + fprintf(fp, "%s\n", (char *)lp->data); + } + fprintf(fp, "\n"); + } + if(info->force) { + fprintf(fp, "%%FORCE%%\n\n"); + } if(local) { - if(info->url[0]) { + if(info->url) { fprintf(fp, "%%URL%%\n" "%s\n\n", info->url); } @@ -584,7 +694,7 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) } fprintf(fp, "\n"); } - if(info->arch[0]) { + if(info->arch) { fprintf(fp, "%%ARCH%%\n" "%s\n\n", info->arch); } @@ -596,7 +706,7 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) fprintf(fp, "%%INSTALLDATE%%\n" "%ju\n\n", (uintmax_t)info->installdate); } - if(info->packager[0]) { + if(info->packager) { fprintf(fp, "%%PACKAGER%%\n" "%s\n\n", info->packager); } @@ -695,19 +805,6 @@ int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq) } fprintf(fp, "\n"); } - if(!local) { - if(info->replaces) { - fputs("%REPLACES%\n", fp); - for(lp = info->replaces; lp; lp = lp->next) { - fprintf(fp, "%s\n", (char *)lp->data); - } - fprintf(fp, "\n"); - } - if(info->force) { - fprintf(fp, "%%FORCE%%\n" - "\n"); - } - } fclose(fp); fp = NULL; } @@ -743,63 +840,4 @@ int _alpm_db_remove(pmdb_t *db, pmpkg_t *info) return(0); } -/* - * Return the last update time as number of seconds from the epoch. - * Returns 0 if the value is unknown or can't be read. - */ -time_t _alpm_db_getlastupdate(const pmdb_t *db) -{ - FILE *fp; - char file[PATH_MAX]; - time_t ret = 0; - - ALPM_LOG_FUNC; - - if(db == NULL) { - return(ret); - } - - snprintf(file, PATH_MAX, "%s.lastupdate", db->path); - - /* get the last update time, if it's there */ - if((fp = fopen(file, "r")) == NULL) { - return(ret); - } else { - char line[64]; - if(fgets(line, sizeof(line), fp)) { - ret = atol(line); - } - } - fclose(fp); - return(ret); -} - -/* - * writes the dbpath/.lastupdate file with the value in time - */ -int _alpm_db_setlastupdate(const pmdb_t *db, time_t time) -{ - FILE *fp; - char file[PATH_MAX]; - int ret = 0; - - ALPM_LOG_FUNC; - - if(db == NULL || time == 0) { - return(-1); - } - - snprintf(file, PATH_MAX, "%s.lastupdate", db->path); - - if((fp = fopen(file, "w")) == NULL) { - return(-1); - } - if(fprintf(fp, "%ju", (uintmax_t)time) <= 0) { - ret = -1; - } - fclose(fp); - - return(ret); -} - /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c new file mode 100644 index 00000000..85112fd4 --- /dev/null +++ b/lib/libalpm/be_package.c @@ -0,0 +1,285 @@ +/* + * be_package.c + * + * Copyright (c) 2002-2008 by Judd Vinet <jvinet@zeroflux.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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <ctype.h> +#include <locale.h> /* setlocale */ + +/* libarchive */ +#include <archive.h> +#include <archive_entry.h> + +/* libalpm */ +#include "alpm_list.h" +#include "util.h" +#include "log.h" +#include "package.h" +#include "deps.h" /* _alpm_splitdep */ + +/** + * Parses the package description file for a package into a pmpkg_t struct. + * @param archive the archive to read from, pointed at the .PKGINFO entry + * @param newpkg an empty pmpkg_t struct to fill with package info + * + * @return 0 on success, 1 on error + */ +static int parse_descfile(struct archive *a, pmpkg_t *newpkg) +{ + char line[PATH_MAX]; + char *ptr = NULL; + char *key = NULL; + int linenum = 0; + + ALPM_LOG_FUNC; + + /* loop until we reach EOF (where archive_fgets will return NULL) */ + while(_alpm_archive_fgets(line, PATH_MAX, a) != NULL) { + linenum++; + _alpm_strtrim(line); + if(strlen(line) == 0 || line[0] == '#') { + continue; + } + ptr = line; + key = strsep(&ptr, "="); + if(key == NULL || ptr == NULL) { + _alpm_log(PM_LOG_DEBUG, "%s: syntax error in description file line %d\n", + newpkg->name ? newpkg->name : "error", linenum); + } else { + key = _alpm_strtrim(key); + ptr = _alpm_strtrim(ptr); + if(!strcmp(key, "pkgname")) { + STRDUP(newpkg->name, ptr, RET_ERR(PM_ERR_MEMORY, -1)); + } else if(!strcmp(key, "pkgver")) { + STRDUP(newpkg->version, ptr, RET_ERR(PM_ERR_MEMORY, -1)); + } else if(!strcmp(key, "pkgdesc")) { + STRDUP(newpkg->desc, ptr, RET_ERR(PM_ERR_MEMORY, -1)); + } else if(!strcmp(key, "group")) { + newpkg->groups = alpm_list_add(newpkg->groups, strdup(ptr)); + } else if(!strcmp(key, "url")) { + STRDUP(newpkg->url, ptr, RET_ERR(PM_ERR_MEMORY, -1)); + } else if(!strcmp(key, "license")) { + newpkg->licenses = alpm_list_add(newpkg->licenses, strdup(ptr)); + } else if(!strcmp(key, "builddate")) { + char first = tolower(ptr[0]); + if(first > 'a' && first < 'z') { + struct tm tmp_tm = {0}; //initialize to null in case of failure + setlocale(LC_TIME, "C"); + strptime(ptr, "%a %b %e %H:%M:%S %Y", &tmp_tm); + newpkg->builddate = mktime(&tmp_tm); + setlocale(LC_TIME, ""); + } else { + newpkg->builddate = atol(ptr); + } + } else if(!strcmp(key, "packager")) { + STRDUP(newpkg->packager, ptr, RET_ERR(PM_ERR_MEMORY, -1)); + } else if(!strcmp(key, "arch")) { + STRDUP(newpkg->arch, ptr, RET_ERR(PM_ERR_MEMORY, -1)); + } else if(!strcmp(key, "size")) { + /* size in the raw package is uncompressed (installed) size */ + newpkg->isize = atol(ptr); + } else if(!strcmp(key, "depend")) { + pmdepend_t *dep = _alpm_splitdep(ptr); + newpkg->depends = alpm_list_add(newpkg->depends, dep); + } else if(!strcmp(key, "optdepend")) { + newpkg->optdepends = alpm_list_add(newpkg->optdepends, strdup(ptr)); + } else if(!strcmp(key, "conflict")) { + newpkg->conflicts = alpm_list_add(newpkg->conflicts, strdup(ptr)); + } else if(!strcmp(key, "replaces")) { + newpkg->replaces = alpm_list_add(newpkg->replaces, strdup(ptr)); + } else if(!strcmp(key, "provides")) { + newpkg->provides = alpm_list_add(newpkg->provides, strdup(ptr)); + } else if(!strcmp(key, "backup")) { + newpkg->backup = alpm_list_add(newpkg->backup, strdup(ptr)); + } else { + _alpm_log(PM_LOG_DEBUG, "%s: syntax error in description file line %d\n", + newpkg->name ? newpkg->name : "error", linenum); + } + } + line[0] = '\0'; + } + + return(0); +} + +/** + * Load a package and create the corresponding pmpkg_t struct. + * @param pkgfile path to the package file + * @param full whether to stop the load after metadata is read or continue + * through the full archive + * @return An information filled pmpkg_t struct + */ +static pmpkg_t *pkg_load(const char *pkgfile, unsigned short full) +{ + int ret = ARCHIVE_OK; + int config = 0; + struct archive *archive; + struct archive_entry *entry; + pmpkg_t *newpkg = NULL; + struct stat st; + + ALPM_LOG_FUNC; + + if(pkgfile == NULL || strlen(pkgfile) == 0) { + RET_ERR(PM_ERR_WRONG_ARGS, NULL); + } + + if((archive = archive_read_new()) == NULL) { + RET_ERR(PM_ERR_LIBARCHIVE, NULL); + } + + archive_read_support_compression_all(archive); + archive_read_support_format_all(archive); + + if (archive_read_open_filename(archive, pkgfile, + ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { + RET_ERR(PM_ERR_PKG_OPEN, NULL); + } + + newpkg = _alpm_pkg_new(); + if(newpkg == NULL) { + archive_read_finish(archive); + RET_ERR(PM_ERR_MEMORY, NULL); + } + + if(stat(pkgfile, &st) == 0) { + newpkg->size = st.st_size; + } + + /* If full is false, only read through the archive until we find our needed + * metadata. If it is true, read through the entire archive, which serves + * as a verfication of integrity and allows us to create the filelist. */ + while((ret = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) { + const char *entry_name = archive_entry_pathname(entry); + + if(strcmp(entry_name, ".PKGINFO") == 0) { + /* parse the info file */ + if(parse_descfile(archive, newpkg) != 0) { + _alpm_log(PM_LOG_ERROR, _("could not parse package description file in %s\n"), + pkgfile); + goto pkg_invalid; + } + if(newpkg->name == NULL || strlen(newpkg->name) == 0) { + _alpm_log(PM_LOG_ERROR, _("missing package name in %s\n"), pkgfile); + goto pkg_invalid; + } + if(newpkg->version == NULL || strlen(newpkg->version) == 0) { + _alpm_log(PM_LOG_ERROR, _("missing package version in %s\n"), pkgfile); + goto pkg_invalid; + } + config = 1; + continue; + } else if(strcmp(entry_name, ".INSTALL") == 0) { + newpkg->scriptlet = 1; + } else if(*entry_name == '.') { + /* for now, ignore all files starting with '.' that haven't + * already been handled (for future possibilities) */ + } else { + /* Keep track of all files for filelist generation */ + newpkg->files = alpm_list_add(newpkg->files, strdup(entry_name)); + } + + if(archive_read_data_skip(archive)) { + _alpm_log(PM_LOG_ERROR, _("error while reading package %s: %s\n"), + pkgfile, archive_error_string(archive)); + pm_errno = PM_ERR_LIBARCHIVE; + goto error; + } + + /* if we are not doing a full read, see if we have all we need */ + if(!full && config) { + break; + } + } + + if(ret != ARCHIVE_EOF && ret != ARCHIVE_OK) { /* An error occured */ + _alpm_log(PM_LOG_ERROR, _("error while reading package %s: %s\n"), + pkgfile, archive_error_string(archive)); + pm_errno = PM_ERR_LIBARCHIVE; + goto error; + } + + if(!config) { + _alpm_log(PM_LOG_ERROR, _("missing package metadata in %s\n"), pkgfile); + goto pkg_invalid; + } + + archive_read_finish(archive); + + /* internal fields for package struct */ + newpkg->origin = PKG_FROM_FILE; + newpkg->origin_data.file = strdup(pkgfile); + + if(full) { + /* "checking for conflicts" requires a sorted list, ensure that here */ + _alpm_log(PM_LOG_DEBUG, "sorting package filelist for %s\n", pkgfile); + newpkg->files = alpm_list_msort(newpkg->files, alpm_list_count(newpkg->files), + _alpm_str_cmp); + newpkg->infolevel = INFRQ_ALL; + } else { + /* get rid of any partial filelist we may have collected, it is invalid */ + FREELIST(newpkg->files); + newpkg->infolevel = INFRQ_BASE | INFRQ_DESC | INFRQ_DEPENDS; + } + + return(newpkg); + +pkg_invalid: + pm_errno = PM_ERR_PKG_INVALID; +error: + _alpm_pkg_free(newpkg); + archive_read_finish(archive); + + return(NULL); +} + +/** Create a package from a file. + * If full is false, the archive is read only until all necessary + * metadata is found. If it is true, the entire archive is read, which + * serves as a verfication of integrity and the filelist can be created. + * @param filename location of the package tarball + * @param full whether to stop the load after metadata is read or continue + * through the full archive + * @param pkg address of the package pointer + * @return 0 on success, -1 on error (pm_errno is set accordingly) + */ +int SYMEXPORT alpm_pkg_load(const char *filename, unsigned short full, + pmpkg_t **pkg) +{ + ALPM_LOG_FUNC; + + /* Sanity checks */ + ASSERT(filename != NULL && strlen(filename) != 0, + RET_ERR(PM_ERR_WRONG_ARGS, -1)); + ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1)); + + *pkg = pkg_load(filename, full); + if(*pkg == NULL) { + /* pm_errno is set by pkg_load */ + return(-1); + } + + return(0); +} + +/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/cache.c b/lib/libalpm/cache.c index 0ad923a5..b140476c 100644 --- a/lib/libalpm/cache.c +++ b/lib/libalpm/cache.c @@ -31,7 +31,6 @@ #include "log.h" #include "alpm.h" #include "util.h" -#include "error.h" #include "package.h" #include "group.h" #include "db.h" @@ -41,32 +40,21 @@ */ int _alpm_db_load_pkgcache(pmdb_t *db) { - pmpkg_t *info; - int count = 0; - ALPM_LOG_FUNC; if(db == NULL) { return(-1); } - _alpm_db_free_pkgcache(db); _alpm_log(PM_LOG_DEBUG, "loading package cache for repository '%s'\n", - db->treename); - - _alpm_db_rewind(db); - while((info = _alpm_db_scan(db, NULL)) != NULL) { - _alpm_log(PM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n", - alpm_pkg_get_name(info), db->treename); - info->origin = PKG_FROM_CACHE; - info->origin_data.db = db; - /* add to the collection */ - db->pkgcache = alpm_list_add(db->pkgcache, info); - count++; + db->treename); + if(_alpm_db_populate(db) == -1) { + _alpm_log(PM_LOG_DEBUG, + "failed to load package cache for repository '%s'\n", db->treename); + return(-1); } - db->pkgcache = alpm_list_msort(db->pkgcache, count, _alpm_pkg_cmp); return(0); } @@ -81,10 +69,7 @@ void _alpm_db_free_pkgcache(pmdb_t *db) _alpm_log(PM_LOG_DEBUG, "freeing package cache for repository '%s'\n", db->treename); - alpm_list_t *tmp; - for(tmp = db->pkgcache; tmp; tmp = alpm_list_next(tmp)) { - _alpm_pkg_free(tmp->data); - } + alpm_list_free_inner(db->pkgcache, (alpm_list_fn_free)_alpm_pkg_free); alpm_list_free(db->pkgcache); db->pkgcache = NULL; @@ -115,21 +100,15 @@ alpm_list_t *_alpm_db_get_pkgcache(pmdb_t *db) int _alpm_db_add_pkgincache(pmdb_t *db, pmpkg_t *pkg) { - pmpkg_t *newpkg; - ALPM_LOG_FUNC; if(db == NULL || pkg == NULL) { return(-1); } - newpkg = _alpm_pkg_dup(pkg); - if(newpkg == NULL) { - return(-1); - } _alpm_log(PM_LOG_DEBUG, "adding entry '%s' in '%s' cache\n", - alpm_pkg_get_name(newpkg), db->treename); - db->pkgcache = alpm_list_add_sorted(db->pkgcache, newpkg, _alpm_pkg_cmp); + alpm_pkg_get_name(pkg), db->treename); + db->pkgcache = alpm_list_add_sorted(db->pkgcache, pkg, _alpm_pkg_cmp); _alpm_db_free_grpcache(db); @@ -181,7 +160,7 @@ pmpkg_t *_alpm_db_get_pkgfromcache(pmdb_t *db, const char *target) return(NULL); } - return(_alpm_pkg_find(target, pkgcache)); + return(_alpm_pkg_find(pkgcache, target)); } /* Returns a new group cache from db. @@ -208,33 +187,29 @@ int _alpm_db_load_grpcache(pmdb_t *db) pmpkg_t *pkg = lp->data; for(i = alpm_pkg_get_groups(pkg); i; i = i->next) { - if(!alpm_list_find_str(db->grpcache, i->data)) { - pmgrp_t *grp = _alpm_grp_new(); - - strncpy(grp->name, i->data, GRP_NAME_LEN); - grp->name[GRP_NAME_LEN-1] = '\0'; - grp->packages = alpm_list_add_sorted(grp->packages, - /* gross signature forces us to - * discard const */ - (void*)alpm_pkg_get_name(pkg), - _alpm_str_cmp); - db->grpcache = alpm_list_add_sorted(db->grpcache, grp, _alpm_grp_cmp); - } else { - alpm_list_t *j; - - for(j = db->grpcache; j; j = j->next) { - pmgrp_t *grp = j->data; - - if(strcmp(grp->name, i->data) == 0) { - const char *pkgname = alpm_pkg_get_name(pkg); - if(!alpm_list_find_str(grp->packages, pkgname)) { - grp->packages = alpm_list_add_sorted(grp->packages, - (void*)pkgname, - _alpm_str_cmp); - } - } + const char *grpname = i->data; + alpm_list_t *j; + pmgrp_t *grp = NULL; + int found = 0; + + /* first look through the group cache for a group with this name */ + for(j = db->grpcache; j; j = j->next) { + grp = j->data; + + if(strcmp(grp->name, grpname) == 0 + && !alpm_list_find_ptr(grp->packages, pkg)) { + grp->packages = alpm_list_add(grp->packages, pkg); + found = 1; + break; } } + if(found) { + continue; + } + /* we didn't find the group, so create a new one with this name */ + grp = _alpm_grp_new(grpname); + grp->packages = alpm_list_add(grp->packages, pkg); + db->grpcache = alpm_list_add(db->grpcache, grp); } } @@ -252,10 +227,6 @@ void _alpm_db_free_grpcache(pmdb_t *db) } for(lg = db->grpcache; lg; lg = lg->next) { - pmgrp_t *grp = lg->data; - - alpm_list_free(grp->packages); - grp->packages = NULL; _alpm_grp_free(lg->data); lg->data = NULL; } diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c index 3442902c..a8bcdd59 100644 --- a/lib/libalpm/conflict.c +++ b/lib/libalpm/conflict.c @@ -36,7 +36,6 @@ #include "handle.h" #include "trans.h" #include "util.h" -#include "error.h" #include "log.h" #include "cache.h" #include "deps.h" @@ -49,12 +48,30 @@ pmconflict_t *_alpm_conflict_new(const char *package1, const char *package2) MALLOC(conflict, sizeof(pmconflict_t), RET_ERR(PM_ERR_MEMORY, NULL)); - strncpy(conflict->package1, package1, PKG_NAME_LEN); - strncpy(conflict->package2, package2, PKG_NAME_LEN); + STRDUP(conflict->package1, package1, RET_ERR(PM_ERR_MEMORY, NULL)); + STRDUP(conflict->package2, package2, RET_ERR(PM_ERR_MEMORY, NULL)); return(conflict); } +void _alpm_conflict_free(pmconflict_t *conflict) +{ + FREE(conflict->package2); + FREE(conflict->package1); + FREE(conflict); +} + +pmconflict_t *_alpm_conflict_dup(const pmconflict_t *conflict) +{ + pmconflict_t *newconflict; + CALLOC(newconflict, 1, sizeof(pmconflict_t), RET_ERR(PM_ERR_MEMORY, NULL)); + + STRDUP(newconflict->package1, conflict->package1, RET_ERR(PM_ERR_MEMORY, NULL)); + STRDUP(newconflict->package2, conflict->package2, RET_ERR(PM_ERR_MEMORY, NULL)); + + return(newconflict); +} + int _alpm_conflict_isin(pmconflict_t *needle, alpm_list_t *haystack) { alpm_list_t *i; @@ -86,7 +103,7 @@ static int does_conflict(pmpkg_t *pkg1, const char *conflict, pmpkg_t *pkg2) { const char *pkg1name = alpm_pkg_get_name(pkg1); const char *pkg2name = alpm_pkg_get_name(pkg2); - pmdepend_t *conf = alpm_splitdep(conflict); + pmdepend_t *conf = _alpm_splitdep(conflict); int match = 0; match = alpm_depcmp(pkg2, conf); @@ -94,7 +111,7 @@ static int does_conflict(pmpkg_t *pkg1, const char *conflict, pmpkg_t *pkg2) _alpm_log(PM_LOG_DEBUG, "package %s conflicts with %s (by %s)\n", pkg1name, pkg2name, conflict); } - FREE(conf); + _alpm_dep_free(conf); return(match); } @@ -110,7 +127,7 @@ static void add_conflict(alpm_list_t **baddeps, const char *pkg1, if(conflict && !_alpm_conflict_isin(conflict, *baddeps)) { *baddeps = alpm_list_add(*baddeps, conflict); } else { - FREE(conflict); + _alpm_conflict_free(conflict); } } @@ -200,9 +217,13 @@ alpm_list_t *_alpm_outerconflicts(pmdb_t *db, alpm_list_t *packages) return(baddeps); } -/* Check for transaction conflicts */ -alpm_list_t *_alpm_checkconflicts(pmdb_t *db, alpm_list_t *packages) { - return(alpm_list_join(_alpm_innerconflicts(packages), _alpm_outerconflicts(db, packages))); +/** Check the package conflicts in a database + * + * @param db_local the database to check + * @return an alpm_list_t of pmconflict_t + */ +alpm_list_t SYMEXPORT *alpm_checkdbconflicts(pmdb_t *db_local) { + return(_alpm_innerconflicts(_alpm_db_get_pkgcache(db_local))); } /* Returns a alpm_list_t* of file conflicts. @@ -299,15 +320,15 @@ static alpm_list_t *add_fileconflict(alpm_list_t *conflicts, const char* name1, const char* name2) { pmfileconflict_t *conflict; - MALLOC(conflict, sizeof(pmfileconflict_t), return(conflicts)); + MALLOC(conflict, sizeof(pmfileconflict_t), RET_ERR(PM_ERR_MEMORY, NULL)); conflict->type = type; - strncpy(conflict->target, name1, PKG_NAME_LEN); - strncpy(conflict->file, filestr, CONFLICT_FILE_LEN); + STRDUP(conflict->target, name1, RET_ERR(PM_ERR_MEMORY, NULL)); + STRDUP(conflict->file, filestr, RET_ERR(PM_ERR_MEMORY, NULL)); if(name2) { - strncpy(conflict->ctarget, name2, PKG_NAME_LEN); + STRDUP(conflict->ctarget, name2, RET_ERR(PM_ERR_MEMORY, NULL)); } else { - conflict->ctarget[0] = '\0'; + conflict->ctarget = ""; } conflicts = alpm_list_add(conflicts, conflict); @@ -317,6 +338,16 @@ static alpm_list_t *add_fileconflict(alpm_list_t *conflicts, return(conflicts); } +void _alpm_fileconflict_free(pmfileconflict_t *conflict) +{ + if(strlen(conflict->ctarget) > 0) { + FREE(conflict->ctarget); + } + FREE(conflict->file);; + FREE(conflict->target); + FREE(conflict); +} + /* Find file conflicts that may occur during the transaction with two checks: * 1: check every target against every target * 2: check every target against the filesystem */ @@ -351,13 +382,13 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, char *roo PROGRESS(trans, PM_TRANS_PROGRESS_CONFLICTS_START, "", (percent * 100), numtargs, current); /* CHECK 1: check every target against every target */ + _alpm_log(PM_LOG_DEBUG, "searching for file conflicts: %s\n", + alpm_pkg_get_name(p1)); for(j = i->next; j; j = j->next) { p2 = j->data; if(!p2) { continue; } - _alpm_log(PM_LOG_DEBUG, "searching for file conflicts: %s and %s\n", - alpm_pkg_get_name(p1), alpm_pkg_get_name(p2)); tmpfiles = chk_fileconflicts(alpm_pkg_get_files(p1), alpm_pkg_get_files(p2)); if(tmpfiles) { @@ -416,26 +447,6 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, char *roo if(!skip_conflict) { _alpm_log(PM_LOG_DEBUG, "checking possible conflict: %s\n", path); - /* Make sure the possible conflict is not a symlink that points to a - * path in the old package. This is kind of dirty with inode usage */ - /* TODO this seems ripe for a cleanup */ - if(dbpkg) { - struct stat pkgbuf; - char str[PATH_MAX+1]; - unsigned ok = 0; - for(k = dbpkg->files; k; k = k->next) { - snprintf(str, PATH_MAX, "%s%s", root, (char*)k->data); - if(!_alpm_lstat(str, &pkgbuf) && lsbuf.st_ino == pkgbuf.st_ino) { - ok = 1; - _alpm_log(PM_LOG_DEBUG, "conflict was a symlink: %s\n", path); - break; - } - } - if(ok == 1) { - continue; - } - } - /* Look at all the targets to see if file has changed hands */ int resolved_conflict = 0; /* have we acted on this conflict? */ for(k = targets; k; k = k->next) { diff --git a/lib/libalpm/conflict.h b/lib/libalpm/conflict.h index a846aace..71ed579d 100644 --- a/lib/libalpm/conflict.h +++ b/lib/libalpm/conflict.h @@ -23,27 +23,28 @@ #include "db.h" #include "package.h" -#define CONFLICT_FILE_LEN 512 - struct __pmconflict_t { - char package1[PKG_NAME_LEN]; - char package2[PKG_NAME_LEN]; + char *package1; + char *package2; }; struct __pmfileconflict_t { - char target[PKG_NAME_LEN]; + char *target; pmfileconflicttype_t type; - char file[CONFLICT_FILE_LEN]; - char ctarget[PKG_NAME_LEN]; + char *file; + char *ctarget; }; pmconflict_t *_alpm_conflict_new(const char *package1, const char *package2); +pmconflict_t *_alpm_conflict_dup(const pmconflict_t *conflict); +void _alpm_conflict_free(pmconflict_t *conflict); int _alpm_conflict_isin(pmconflict_t *needle, alpm_list_t *haystack); alpm_list_t *_alpm_innerconflicts(alpm_list_t *packages); alpm_list_t *_alpm_outerconflicts(pmdb_t *db, alpm_list_t *packages); -alpm_list_t *_alpm_checkconflicts(pmdb_t *db, alpm_list_t *packages); alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, char *root); +void _alpm_fileconflict_free(pmfileconflict_t *conflict); + #endif /* _ALPM_CONFLICT_H */ /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c index 1485c34a..df16c3c9 100644 --- a/lib/libalpm/db.c +++ b/lib/libalpm/db.c @@ -39,8 +39,6 @@ #include "alpm_list.h" #include "log.h" #include "util.h" -#include "error.h" -#include "server.h" #include "handle.h" #include "cache.h" #include "alpm.h" @@ -190,14 +188,9 @@ int SYMEXPORT alpm_db_setserver(pmdb_t *db, const char *url) } if(url && strlen(url)) { - pmserver_t *server; - if((server = _alpm_server_new(url)) == NULL) { - /* pm_errno is set by _alpm_server_new */ - return(-1); - } - db->servers = alpm_list_add(db->servers, server); - _alpm_log(PM_LOG_DEBUG, "adding new server to database '%s': protocol '%s', server '%s', path '%s'\n", - db->treename, server->s_url->scheme, server->s_url->host, server->s_url->doc); + db->servers = alpm_list_add(db->servers, strdup(url)); + _alpm_log(PM_LOG_DEBUG, "adding new server URL to database '%s': %s\n", + db->treename, url); } else { FREELIST(db->servers); _alpm_log(PM_LOG_DEBUG, "serverlist flushed for '%s'\n", db->treename); @@ -206,98 +199,6 @@ int SYMEXPORT alpm_db_setserver(pmdb_t *db, const char *url) return(0); } -/** Update a package database - * @param force if true, then forces the update, otherwise update only in case - * the database isn't up to date - * @param db pointer to the package database to update - * @return 0 on success, > 0 on error (pm_errno is set accordingly), < 0 if up - * to date - */ -int SYMEXPORT alpm_db_update(int force, pmdb_t *db) -{ - alpm_list_t *lp; - char path[PATH_MAX]; - alpm_list_t *files = NULL; - time_t newmtime = 0, lastupdate = 0; - const char *dbpath; - int ret; - - ALPM_LOG_FUNC; - - /* Sanity checks */ - ASSERT(handle != NULL, RET_ERR(PM_ERR_HANDLE_NULL, -1)); - ASSERT(db != NULL && db != handle->db_local, RET_ERR(PM_ERR_WRONG_ARGS, -1)); - /* Verify we are in a transaction. This is done _mainly_ because we need a DB - * lock - if we update without a db lock, we may kludge some other pacman - * process that _has_ a lock. - */ - ASSERT(handle->trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1)); - ASSERT(handle->trans->state == STATE_INITIALIZED, RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1)); - ASSERT(handle->trans->type == PM_TRANS_TYPE_SYNC, RET_ERR(PM_ERR_TRANS_TYPE, -1)); - - if(!alpm_list_find_ptr(handle->dbs_sync, db)) { - RET_ERR(PM_ERR_DB_NOT_FOUND, -1); - } - - if(!force) { - /* get the lastupdate time */ - lastupdate = _alpm_db_getlastupdate(db); - if(lastupdate == 0) { - _alpm_log(PM_LOG_DEBUG, "failed to get lastupdate time for %s\n", - db->treename); - } - } - - /* build a one-element list */ - snprintf(path, PATH_MAX, "%s" DBEXT, db->treename); - files = alpm_list_add(files, strdup(path)); - - dbpath = alpm_option_get_dbpath(); - - ret = _alpm_downloadfiles_forreal(db->servers, dbpath, files, lastupdate, - &newmtime, NULL, 0); - FREELIST(files); - if(ret == 1) { - /* mtimes match, do nothing */ - pm_errno = 0; - return(1); - } else if(ret == -1) { - /* we use downloadLastErrString and downloadLastErrCode here, error returns from - * libdownload */ - _alpm_log(PM_LOG_DEBUG, "failed to sync db: %s [%d]\n", - downloadLastErrString, downloadLastErrCode); - RET_ERR(PM_ERR_DB_SYNC, -1); - } else { - if(newmtime != 0) { - _alpm_log(PM_LOG_DEBUG, "sync: new mtime for %s: %ju\n", - db->treename, (uintmax_t)newmtime); - _alpm_db_setlastupdate(db, newmtime); - } - snprintf(path, PATH_MAX, "%s%s" DBEXT, dbpath, db->treename); - - /* remove the old dir */ - _alpm_log(PM_LOG_DEBUG, "flushing database %s\n", db->path); - for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) { - pmpkg_t *pkg = lp->data; - if(pkg && _alpm_db_remove(db, pkg) == -1) { - _alpm_log(PM_LOG_ERROR, _("could not remove database entry %s%s\n"), db->treename, - alpm_pkg_get_name(pkg)); - RET_ERR(PM_ERR_DB_REMOVE, -1); - } - } - - /* Cache needs to be rebuild */ - _alpm_db_free_pkgcache(db); - - /* uncompress the sync database */ - if(_alpm_db_install(db, path) == -1) { - return -1; - } - } - - return(0); -} - /** Get the name of a package database * @param db pointer to the package database * @return the name of the package database, NULL on error @@ -319,8 +220,7 @@ const char SYMEXPORT *alpm_db_get_name(const pmdb_t *db) */ const char SYMEXPORT *alpm_db_get_url(const pmdb_t *db) { - char path[PATH_MAX]; - pmserver_t *s; + char *url; ALPM_LOG_FUNC; @@ -328,10 +228,9 @@ const char SYMEXPORT *alpm_db_get_url(const pmdb_t *db) ASSERT(handle != NULL, return(NULL)); ASSERT(db != NULL, return(NULL)); - s = (pmserver_t*)db->servers->data; + url = (char*)db->servers->data; - snprintf(path, PATH_MAX, "%s://%s%s", s->s_url->scheme, s->s_url->host, s->s_url->doc); - return strdup(path); + return(url); } @@ -367,23 +266,6 @@ alpm_list_t SYMEXPORT *alpm_db_getpkgcache(pmdb_t *db) return(_alpm_db_get_pkgcache(db)); } -/** Get the list of packages that a package provides - * @param db pointer to the package database to get the package from - * @param name name of the package - * @return the list of packages on success, NULL on error - */ -alpm_list_t SYMEXPORT *alpm_db_whatprovides(pmdb_t *db, const char *name) -{ - ALPM_LOG_FUNC; - - /* Sanity checks */ - ASSERT(handle != NULL, return(NULL)); - ASSERT(db != NULL, return(NULL)); - ASSERT(name != NULL && strlen(name) != 0, return(NULL)); - - return(_alpm_db_whatprovides(db, name)); -} - /** Get a group entry from a package database * @param db pointer to the package database to get the group from * @param name of the group @@ -445,35 +327,31 @@ pmdb_t *_alpm_db_new(const char *dbpath, const char *treename) CALLOC(db->path, 1, pathsize, RET_ERR(PM_ERR_MEMORY, NULL)); sprintf(db->path, "%s%s/", dbpath, treename); - - strncpy(db->treename, treename, PATH_MAX); + STRDUP(db->treename, treename, RET_ERR(PM_ERR_MEMORY, NULL)); return(db); } void _alpm_db_free(pmdb_t *db) { - alpm_list_t *tmp; - ALPM_LOG_FUNC; /* cleanup pkgcache */ _alpm_db_free_pkgcache(db); /* cleanup server list */ - for(tmp = db->servers; tmp; tmp = alpm_list_next(tmp)) { - _alpm_server_free(tmp->data); - } - alpm_list_free(db->servers); + FREELIST(db->servers); FREE(db->path); + FREE(db->treename); FREE(db); return; } -int _alpm_db_cmp(const void *db1, const void *db2) +int _alpm_db_cmp(const void *d1, const void *d2) { - ALPM_LOG_FUNC; - return(strcmp(((pmdb_t *)db1)->treename, ((pmdb_t *)db2)->treename)); + pmdb_t *db1 = (pmdb_t *)db1; + pmdb_t *db2 = (pmdb_t *)db2; + return(strcmp(db1->treename, db2->treename)); } alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles) @@ -500,18 +378,16 @@ alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles) for(j = _alpm_db_get_pkgcache(db); j; j = j->next) { pmpkg_t *pkg = j->data; const char *matched = NULL; + const char *name = alpm_pkg_get_name(pkg); + const char *desc = alpm_pkg_get_desc(pkg); - /* check name */ - if (regexec(®, alpm_pkg_get_name(pkg), 0, 0, 0) == 0) { - matched = alpm_pkg_get_name(pkg); - } - /* check plain text name */ - else if (strstr(alpm_pkg_get_name(pkg), targ)) { - matched = alpm_pkg_get_name(pkg); + /* check name as regex AND as plain text */ + if(name && (regexec(®, name, 0, 0, 0) == 0 || strstr(name, targ))) { + matched = name; } /* check desc */ - else if (regexec(®, alpm_pkg_get_desc(pkg), 0, 0, 0) == 0) { - matched = alpm_pkg_get_desc(pkg); + else if (desc && regexec(®, desc, 0, 0, 0) == 0) { + matched = desc; } /* check provides */ /* TODO: should we be doing this, and should we print something @@ -641,47 +517,4 @@ pmdb_t *_alpm_db_register_sync(const char *treename) return(db); } -/* helper function for alpm_list_find and _alpm_db_whatprovides - * - * @return "provision.name" == needle (as string) - */ -int _alpm_prov_cmp(const void *provision, const void *needle) -{ - char *tmpptr; - char *provname = strdup(provision); - int retval = 0; - tmpptr = strchr(provname, '='); - - if(tmpptr != NULL) { /* provision-version */ - *tmpptr='\0'; - } - retval = strcmp(provname, needle); - free(provname); - return(retval); -} - -/* return a alpm_list_t of packages in "db" that provide "package" - */ -alpm_list_t *_alpm_db_whatprovides(pmdb_t *db, const char *package) -{ - alpm_list_t *pkgs = NULL; - alpm_list_t *lp; - - ALPM_LOG_FUNC; - - if(db == NULL || package == NULL || strlen(package) == 0) { - return(NULL); - } - - for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) { - pmpkg_t *info = lp->data; - - if(alpm_list_find(alpm_pkg_get_provides(info), (const void *)package, _alpm_prov_cmp)) { - pkgs = alpm_list_add(pkgs, info); - } - } - - return(pkgs); -} - /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h index 8c8c9bd7..eb0af1ae 100644 --- a/lib/libalpm/db.h +++ b/lib/libalpm/db.h @@ -40,7 +40,7 @@ typedef enum _pmdbinfrq_t { /* Database */ struct __pmdb_t { char *path; - char treename[PATH_MAX]; + char *treename; void *handle; alpm_list_t *pkgcache; alpm_list_t *grpcache; @@ -55,21 +55,13 @@ alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles); pmdb_t *_alpm_db_register_local(void); pmdb_t *_alpm_db_register_sync(const char *treename); -/* Provision */ -int _alpm_prov_cmp(const void *provision, const void *needle); -alpm_list_t *_alpm_db_whatprovides(pmdb_t *db, const char *package); - /* be.c, backend specific calls */ -int _alpm_db_install(pmdb_t *db, const char *dbfile); int _alpm_db_open(pmdb_t *db); void _alpm_db_close(pmdb_t *db); -void _alpm_db_rewind(pmdb_t *db); -pmpkg_t *_alpm_db_scan(pmdb_t *db, const char *target); +int _alpm_db_populate(pmdb_t *db); int _alpm_db_read(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq); int _alpm_db_write(pmdb_t *db, pmpkg_t *info, pmdbinfrq_t inforeq); int _alpm_db_remove(pmdb_t *db, pmpkg_t *info); -time_t _alpm_db_getlastupdate(const pmdb_t *db); -int _alpm_db_setlastupdate(const pmdb_t *db, time_t time); #endif /* _ALPM_DB_H */ diff --git a/lib/libalpm/delta.c b/lib/libalpm/delta.c index 3d33c595..fdb4d99b 100644 --- a/lib/libalpm/delta.c +++ b/lib/libalpm/delta.c @@ -1,7 +1,7 @@ /* * delta.c * - * Copyright (c) 2007 by Judd Vinet <jvinet@zeroflux.org> + * Copyright (c) 2007-2008 by Judd Vinet <jvinet@zeroflux.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,14 +21,14 @@ #include <stdlib.h> #include <string.h> +#include <limits.h> /* libalpm */ #include "delta.h" -#include "error.h" +#include "alpm_list.h" #include "util.h" #include "log.h" -#include "alpm_list.h" -#include "alpm.h" +#include "graph.h" /** \addtogroup alpm_deltas Delta Functions * @brief Functions to manipulate libalpm deltas @@ -37,200 +37,222 @@ const char SYMEXPORT *alpm_delta_get_from(pmdelta_t *delta) { - ALPM_LOG_FUNC; - - /* Sanity checks */ ASSERT(delta != NULL, return(NULL)); - return(delta->from); } -const char SYMEXPORT *alpm_delta_get_to(pmdelta_t *delta) +const char SYMEXPORT *alpm_delta_get_from_md5sum(pmdelta_t *delta) { - ALPM_LOG_FUNC; - - /* Sanity checks */ ASSERT(delta != NULL, return(NULL)); + return(delta->from_md5); +} +const char SYMEXPORT *alpm_delta_get_to(pmdelta_t *delta) +{ + ASSERT(delta != NULL, return(NULL)); return(delta->to); } -unsigned long SYMEXPORT alpm_delta_get_size(pmdelta_t *delta) +const char SYMEXPORT *alpm_delta_get_to_md5sum(pmdelta_t *delta) { - ALPM_LOG_FUNC; - - /* Sanity checks */ - ASSERT(delta != NULL, return(-1)); - - return(delta->size); + ASSERT(delta != NULL, return(NULL)); + return(delta->to_md5); } const char SYMEXPORT *alpm_delta_get_filename(pmdelta_t *delta) { - ALPM_LOG_FUNC; - - /* Sanity checks */ ASSERT(delta != NULL, return(NULL)); - - return(delta->filename); + return(delta->delta); } const char SYMEXPORT *alpm_delta_get_md5sum(pmdelta_t *delta) { - ALPM_LOG_FUNC; - - /* Sanity checks */ ASSERT(delta != NULL, return(NULL)); + return(delta->delta_md5); +} - return(delta->md5sum); +unsigned long SYMEXPORT alpm_delta_get_size(pmdelta_t *delta) +{ + ASSERT(delta != NULL, return(-1)); + return(delta->delta_size); } /** @} */ -/** Calculates the combined size of a list of delta files. - * - * @param deltas the list of pmdelta_t * objects - * - * @return the combined size - */ -unsigned long _alpm_delta_path_size(alpm_list_t *deltas) +static alpm_list_t *delta_graph_init(alpm_list_t *deltas) { - unsigned long sum = 0; - alpm_list_t *dlts = deltas; - - while(dlts) { - pmdelta_t *d = (pmdelta_t *)alpm_list_getdata(dlts); - sum += d->size; + alpm_list_t *i, *j; + alpm_list_t *vertices = NULL; + /* create the vertices */ + for(i = deltas; i; i = i->next) { + char *fpath, *md5sum; + pmgraph_t *v = _alpm_graph_new(); + pmdelta_t *vdelta = i->data; + vdelta->download_size = vdelta->delta_size; + v->weight = ULONG_MAX; + + /* determine whether the delta file already exists */ + fpath = _alpm_filecache_find(vdelta->delta); + md5sum = alpm_get_md5sum(fpath); + if(fpath && md5sum && strcmp(md5sum, vdelta->delta_md5) == 0) { + vdelta->download_size = 0; + } + FREE(fpath); + FREE(md5sum); + + /* determine whether a base 'from' file exists */ + fpath = _alpm_filecache_find(vdelta->from); + md5sum = alpm_get_md5sum(fpath); + if(fpath && md5sum && strcmp(md5sum, vdelta->from_md5) == 0) { + v->weight = vdelta->download_size; + } + FREE(fpath); + FREE(md5sum); - dlts = alpm_list_next(dlts); + v->data = vdelta; + vertices = alpm_list_add(vertices, v); } - return(sum); + /* compute the edges */ + for(i = vertices; i; i = i->next) { + pmgraph_t *v_i = i->data; + pmdelta_t *d_i = v_i->data; + /* loop a second time so we make all possible comparisons */ + for(j = vertices; j; j = j->next) { + pmgraph_t *v_j = j->data; + pmdelta_t *d_j = v_j->data; + /* We want to create a delta tree like the following: + * 1_to_2 + * | + * 1_to_3 2_to_3 + * \ / + * 3_to_4 + * If J 'from' is equal to I 'to', then J is a child of I. + * */ + if(strcmp(d_j->from, d_i->to) == 0 + && strcmp(d_j->from_md5, d_i->to_md5) == 0) { + v_i->children = alpm_list_add(v_i->children, v_j); + } + } + v_i->childptr = v_i->children; + } + return(vertices); } -/** Calculates the combined size of a list of delta files that are not - * in the cache. - * - * @param deltas the list of pmdelta_t * objects - * - * @return the combined size - */ -unsigned long _alpm_delta_path_size_uncached(alpm_list_t *deltas) -{ - unsigned long sum = 0; - alpm_list_t *dlts = deltas; - - while(dlts) { - pmdelta_t *d = (pmdelta_t *)alpm_list_getdata(dlts); - char *fname = _alpm_filecache_find(d->filename); +static unsigned long delta_vert(alpm_list_t *vertices, + const char *to, const char *to_md5, alpm_list_t **path) { + alpm_list_t *i; + pmgraph_t *v; + while(1) { + v = NULL; + /* find the smallest vertice not visited yet */ + for(i = vertices; i; i = i->next) { + pmgraph_t *v_i = i->data; + + if(v_i->state == -1) { + continue; + } - if(!fname) { - sum += d->size; + if(v == NULL || v_i->weight < v->weight) { + v = v_i; + } + } + if(v == NULL || v->weight == ULONG_MAX) { + break; } - FREE(fname); + v->state = -1; - dlts = alpm_list_next(dlts); - } + v->childptr = v->children; + while(v->childptr) { + pmgraph_t *v_c = v->childptr->data; + pmdelta_t *d_c = v_c->data; + if(v_c->weight > v->weight + d_c->download_size) { + v_c->weight = v->weight + d_c->download_size; + v_c->parent = v; + } - return(sum); -} + v->childptr = (v->childptr)->next; -/** Calculates the shortest path from one version to another. - * - * The shortest path is defined as the path with the smallest combined - * size, not the length of the path. - * - * The algorithm is based on Dijkstra's shortest path algorithm. - * - * @param deltas the list of pmdelta_t * objects that a package has - * @param from the version to start from - * @param to the version to end at - * @param path the current path - * - * @return the list of pmdelta_t * objects that has the smallest size. - * NULL (the empty list) is returned if there is no path between the - * versions. - */ -static alpm_list_t *shortest_delta_path(alpm_list_t *deltas, - const char *from, const char *to, alpm_list_t *path) -{ - alpm_list_t *d; - alpm_list_t *shortest = NULL; - - /* Found the 'to' version, this is a good path so return it. */ - if(strcmp(from, to) == 0) { - return(path); + } } - for(d = deltas; d; d = alpm_list_next(d)) { - pmdelta_t *v = alpm_list_getdata(d); + v = NULL; + unsigned long bestsize = 0; - /* If this vertex has already been visited in the path, go to the - * next vertex. */ - if(alpm_list_find_ptr(path, v)) { - continue; - } + for(i = vertices; i; i = i->next) { + pmgraph_t *v_i = i->data; + pmdelta_t *d_i = v_i->data; - /* Once we find a vertex that starts at the 'from' version, - * recursively find the shortest path using the 'to' version of this - * current vertex as the 'from' version in the function call. */ - if(strcmp(v->from, from) == 0) { - alpm_list_t *newpath = alpm_list_copy(path); - newpath = alpm_list_add(newpath, v); - newpath = shortest_delta_path(deltas, v->to, to, newpath); - - if(newpath != NULL) { - /* The path returned works, now use it unless there is already a - * shorter path found. */ - if(shortest == NULL) { - shortest = newpath; - } else if(_alpm_delta_path_size(shortest) > _alpm_delta_path_size(newpath)) { - alpm_list_free(shortest); - shortest = newpath; - } else { - alpm_list_free(newpath); - } + if(strcmp(d_i->to, to) == 0 + || strcmp(d_i->to_md5, to_md5) == 0) { + if(v == NULL || v_i->weight < v->weight) { + v = v_i; + bestsize = v->weight; } } } - alpm_list_free(path); + alpm_list_t *rpath = NULL; + while(v != NULL) { + pmdelta_t *vdelta = v->data; + rpath = alpm_list_add(rpath, vdelta); + v = v->parent; + } + *path = alpm_list_reverse(rpath); + alpm_list_free(rpath); - return(shortest); + return(bestsize); } /** Calculates the shortest path from one version to another. - * * The shortest path is defined as the path with the smallest combined * size, not the length of the path. - * - * @param deltas the list of pmdelta_t * objects that a package has - * @param from the version to start from - * @param to the version to end at - * - * @return the list of pmdelta_t * objects that has the smallest size. - * NULL (the empty list) is returned if there is no path between the - * versions. + * @param deltas the list of pmdelta_t * objects that a file has + * @param to the file to start the search at + * @param to_md5 the md5sum of the above named file + * @param path the pointer to a list location where pmdelta_t * objects that + * have the smallest size are placed. NULL is set if there is no path + * possible with the files available. + * @return the size of the path stored, or ULONG_MAX if path is unfindable */ -alpm_list_t *_alpm_shortest_delta_path(alpm_list_t *deltas, const char *from, - const char *to) +unsigned long _alpm_shortest_delta_path(alpm_list_t *deltas, + const char *to, const char *to_md5, alpm_list_t **path) { - alpm_list_t *path = NULL; + alpm_list_t *bestpath = NULL; + alpm_list_t *vertices; + unsigned long bestsize = ULONG_MAX; + + ALPM_LOG_FUNC; + + if(deltas == NULL) { + *path = NULL; + return(bestsize); + } + + _alpm_log(PM_LOG_DEBUG, "started delta shortest-path search\n"); + + vertices = delta_graph_init(deltas); + + bestsize = delta_vert(vertices, to, to_md5, &bestpath); - path = shortest_delta_path(deltas, from, to, path); + _alpm_log(PM_LOG_DEBUG, "delta shortest-path search complete\n"); - return(path); + alpm_list_free_inner(vertices, _alpm_graph_free); + alpm_list_free(vertices); + + *path = bestpath; + return(bestsize); } /** Parses the string representation of a pmdelta_t object. - * * This function assumes that the string is in the correct format. - * + * This format is as follows: + * $oldfile $oldmd5 $newfile $newmd5 $deltafile $deltamd5 $deltasize * @param line the string to parse - * * @return A pointer to the new pmdelta_t object */ +/* TODO this does not really belong here, but in a parsing lib */ pmdelta_t *_alpm_delta_parse(char *line) { pmdelta_t *delta; @@ -241,26 +263,47 @@ pmdelta_t *_alpm_delta_parse(char *line) tmp2 = tmp; tmp = strchr(tmp, ' '); *(tmp++) = '\0'; - strncpy(delta->from, tmp2, DLT_VERSION_LEN); + STRDUP(delta->from, tmp2, RET_ERR(PM_ERR_MEMORY, NULL)); tmp2 = tmp; tmp = strchr(tmp, ' '); *(tmp++) = '\0'; - strncpy(delta->to, tmp2, DLT_VERSION_LEN); + STRDUP(delta->from_md5, tmp2, RET_ERR(PM_ERR_MEMORY, NULL)); tmp2 = tmp; tmp = strchr(tmp, ' '); *(tmp++) = '\0'; - delta->size = atol(tmp2); + STRDUP(delta->to, tmp2, RET_ERR(PM_ERR_MEMORY, NULL)); tmp2 = tmp; tmp = strchr(tmp, ' '); *(tmp++) = '\0'; - strncpy(delta->filename, tmp2, DLT_FILENAME_LEN); + STRDUP(delta->to_md5, tmp2, RET_ERR(PM_ERR_MEMORY, NULL)); - strncpy(delta->md5sum, tmp, DLT_MD5SUM_LEN); + tmp2 = tmp; + tmp = strchr(tmp, ' '); + *(tmp++) = '\0'; + STRDUP(delta->delta, tmp2, RET_ERR(PM_ERR_MEMORY, NULL)); + + tmp2 = tmp; + tmp = strchr(tmp, ' '); + *(tmp++) = '\0'; + STRDUP(delta->delta_md5, tmp2, RET_ERR(PM_ERR_MEMORY, NULL)); + + delta->delta_size = atol(tmp); return(delta); } +void _alpm_delta_free(pmdelta_t *delta) +{ + FREE(delta->from); + FREE(delta->from_md5); + FREE(delta->to); + FREE(delta->to_md5); + FREE(delta->delta); + FREE(delta->delta_md5); + FREE(delta); +} + /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/delta.h b/lib/libalpm/delta.h index 3065d4d1..33d47e1e 100644 --- a/lib/libalpm/delta.h +++ b/lib/libalpm/delta.h @@ -1,7 +1,7 @@ /* * delta.h * - * Copyright (c) 2007 by Judd Vinet <jvinet@zeroflux.org> + * Copyright (c) 2007-2008 by Judd Vinet <jvinet@zeroflux.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,22 +21,29 @@ #include "alpm.h" -#define DLT_FILENAME_LEN 512 -#define DLT_VERSION_LEN 64 -#define DLT_MD5SUM_LEN 33 - struct __pmdelta_t { - char from[DLT_VERSION_LEN]; - char to[DLT_VERSION_LEN]; - unsigned long size; - char filename[DLT_FILENAME_LEN]; - char md5sum[DLT_MD5SUM_LEN]; + /** filename of the 'before' file */ + char *from; + /** md5sum of the 'before' file */ + char *from_md5; + /** filename of the 'after' file */ + char *to; + /** md5sum of the 'after' file */ + char *to_md5; + /** filename of the delta patch */ + char *delta; + /** md5sum of the delta file */ + char *delta_md5; + /** filesize of the delta file */ + unsigned long delta_size; + /** download filesize of the delta file */ + unsigned long download_size; }; -unsigned long _alpm_delta_path_size(alpm_list_t *deltas); -unsigned long _alpm_delta_path_size_uncached(alpm_list_t *deltas); pmdelta_t *_alpm_delta_parse(char *line); -alpm_list_t *_alpm_shortest_delta_path(alpm_list_t *deltas, const char *from, const char *to); +void _alpm_delta_free(pmdelta_t *delta); +unsigned long _alpm_shortest_delta_path(alpm_list_t *deltas, + const char *to, const char *to_md5, alpm_list_t **path); #endif /* _ALPM_DELTA_H */ diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index b967243d..37e99162 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -30,37 +30,21 @@ #include "alpm_list.h" #include "util.h" #include "log.h" -#include "error.h" +#include "graph.h" #include "package.h" #include "db.h" #include "cache.h" #include "handle.h" -static pmgraph_t *_alpm_graph_new(void) +void _alpm_dep_free(pmdepend_t *dep) { - pmgraph_t *graph = NULL; - - MALLOC(graph, sizeof(pmgraph_t), RET_ERR(PM_ERR_MEMORY, NULL)); - - if(graph) { - graph->state = 0; - graph->data = NULL; - graph->parent = NULL; - graph->children = NULL; - graph->childptr = NULL; - } - return(graph); -} - -static void _alpm_graph_free(void *data) -{ - pmgraph_t *graph = data; - alpm_list_free(graph->children); - free(graph); + FREE(dep->name); + FREE(dep->version); + FREE(dep); } -pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepmod_t depmod, - const char *depname, const char *depversion) +pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepend_t *dep, + const char *causingpkg) { pmdepmissing_t *miss; @@ -68,24 +52,27 @@ pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepmod_t depmod, MALLOC(miss, sizeof(pmdepmissing_t), RET_ERR(PM_ERR_MEMORY, NULL)); - strncpy(miss->target, target, PKG_NAME_LEN); - miss->depend.mod = depmod; - strncpy(miss->depend.name, depname, PKG_NAME_LEN); - if(depversion) { - strncpy(miss->depend.version, depversion, PKG_VERSION_LEN); - } else { - miss->depend.version[0] = 0; - } + STRDUP(miss->target, target, RET_ERR(PM_ERR_MEMORY, NULL)); + miss->depend = _alpm_dep_dup(dep); + STRDUP(miss->causingpkg, causingpkg, RET_ERR(PM_ERR_MEMORY, NULL)); return(miss); } +void _alpm_depmiss_free(pmdepmissing_t *miss) +{ + _alpm_dep_free(miss->depend); + FREE(miss->target); + FREE(miss->causingpkg); + FREE(miss); +} + /* Convert a list of pmpkg_t * to a graph structure, * with a edge for each dependency. * Returns a list of vertices (one vertex = one package) * (used by alpm_sortbydeps) */ -static alpm_list_t *_alpm_graph_init(alpm_list_t *targets) +static alpm_list_t *dep_graph_init(alpm_list_t *targets) { alpm_list_t *i, *j, *k; alpm_list_t *vertices = NULL; @@ -121,20 +108,19 @@ static alpm_list_t *_alpm_graph_init(alpm_list_t *targets) /* Re-order a list of target packages with respect to their dependencies. * - * Example (PM_TRANS_TYPE_ADD): + * Example (reverse == 0): * A depends on C * B depends on A * Target order is A,B,C,D * * Should be re-ordered to C,A,B,D * - * mode should be either PM_TRANS_TYPE_ADD or PM_TRANS_TYPE_REMOVE. This - * affects the dependency order sortbydeps() will use. + * if reverse is > 0, the dependency order will be reversed. * * This function returns the new alpm_list_t* target list. * */ -alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode) +alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, int reverse) { alpm_list_t *newtargs = NULL; alpm_list_t *vertices = NULL; @@ -149,7 +135,7 @@ alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode) _alpm_log(PM_LOG_DEBUG, "started sorting dependencies\n"); - vertices = _alpm_graph_init(targets); + vertices = dep_graph_init(targets); vptr = vertices; vertex = vertices->data; @@ -169,7 +155,7 @@ alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode) pmpkg_t *vertexpkg = vertex->data; pmpkg_t *childpkg = nextchild->data; _alpm_log(PM_LOG_WARNING, _("dependency cycle detected:\n")); - if(mode == PM_TRANS_TYPE_REMOVE) { + if(reverse) { _alpm_log(PM_LOG_WARNING, _("%s will be removed after its %s dependency\n"), vertexpkg->name, childpkg->name); } else { _alpm_log(PM_LOG_WARNING, _("%s will be installed before its %s dependency\n"), vertexpkg->name, childpkg->name); @@ -194,8 +180,8 @@ alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode) _alpm_log(PM_LOG_DEBUG, "sorting dependencies finished\n"); - if(mode == PM_TRANS_TYPE_REMOVE) { - /* we're removing packages, so reverse the order */ + if(reverse) { + /* reverse the order */ alpm_list_t *tmptargs = alpm_list_reverse(newtargs); /* free the old one */ alpm_list_free(newtargs); @@ -208,10 +194,55 @@ alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode) return(newtargs); } -/* Little helper function for alpm_list_find */ -static int satisfycmp(const void *pkg, const void *depend) +alpm_list_t *_alpm_find_dep_satisfiers(alpm_list_t *pkgs, pmdepend_t *dep) { - return(!alpm_depcmp((pmpkg_t*) pkg, (pmdepend_t*) depend)); + alpm_list_t *i, *ret = NULL; + + for(i = pkgs; i; i = alpm_list_next(i)) { + pmpkg_t *pkg = i->data; + if(alpm_depcmp(pkg, dep)) { + ret = alpm_list_add(ret, pkg); + } + } + return(ret); +} + +/** Find packages in a list that provide a given package. + * @param pkgs an alpm_list_t* of package to search + * @param pkgname the name of the package + * @return an alpm_list_t* of packages that provide pkgname + */ +alpm_list_t SYMEXPORT *alpm_find_pkg_satisfiers(alpm_list_t *pkgs, const char *pkgname) +{ + pmdepend_t *dep = _alpm_splitdep(pkgname); + alpm_list_t *res = _alpm_find_dep_satisfiers(pkgs, dep); + _alpm_dep_free(dep); + return(res); +} + +/** Checks dependencies and returns missing ones in a list. + * Dependencies can include versions with depmod operators. + * @param db pointer to the local package database + * @param targets an alpm_list_t* of dependencies strings to satisfy + * @return an alpm_list_t* of missing dependencies strings + */ +alpm_list_t SYMEXPORT *alpm_deptest(pmdb_t *db, alpm_list_t *targets) +{ + alpm_list_t *i, *ret = NULL; + + for(i = targets; i; i = alpm_list_next(i)) { + pmdepend_t *dep; + char *target; + + target = alpm_list_getdata(i); + dep = _alpm_splitdep(target); + + if(!_alpm_find_dep_satisfiers(_alpm_db_get_pkgcache(db), dep)) { + ret = alpm_list_add(ret, target); + } + _alpm_dep_free(dep); + } + return(ret); } /** Checks dependencies and returns missing ones in a list. @@ -257,15 +288,14 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(pmdb_t *db, int reversedeps, pmdepend_t *depend = j->data; /* 1. we check the upgrade list */ /* 2. we check database for untouched satisfying packages */ - if(!alpm_list_find(upgrade, depend, satisfycmp) && - !alpm_list_find(dblist, depend, satisfycmp)) { + if(!_alpm_find_dep_satisfiers(upgrade, depend) && + !_alpm_find_dep_satisfiers(dblist, depend)) { /* Unsatisfied dependency in the upgrade list */ char *missdepstring = alpm_dep_get_string(depend); _alpm_log(PM_LOG_DEBUG, "checkdeps: missing dependency '%s' for package '%s'\n", missdepstring, alpm_pkg_get_name(tp)); free(missdepstring); - miss = _alpm_depmiss_new(alpm_pkg_get_name(tp), depend->mod, - depend->name, depend->version); + miss = _alpm_depmiss_new(alpm_pkg_get_name(tp), depend, ""); baddeps = alpm_list_add(baddeps, miss); } } @@ -278,18 +308,18 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(pmdb_t *db, int reversedeps, pmpkg_t *lp = i->data; for(j = alpm_pkg_get_depends(lp); j; j = j->next) { pmdepend_t *depend = j->data; + pmpkg_t *causingpkg = alpm_list_getdata(_alpm_find_dep_satisfiers(modified, depend)); /* we won't break this depend, if it is already broken, we ignore it */ /* 1. check upgrade list for satisfiers */ /* 2. check dblist for satisfiers */ - if(alpm_list_find(modified, depend, satisfycmp) && - !alpm_list_find(upgrade, depend, satisfycmp) && - !alpm_list_find(dblist, depend, satisfycmp)) { + if(causingpkg && + !_alpm_find_dep_satisfiers(upgrade, depend) && + !_alpm_find_dep_satisfiers(dblist, depend)) { char *missdepstring = alpm_dep_get_string(depend); _alpm_log(PM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n", missdepstring, alpm_pkg_get_name(lp)); free(missdepstring); - miss = _alpm_depmiss_new(lp->name, depend->mod, - depend->name, depend->version); + miss = _alpm_depmiss_new(lp->name, depend, alpm_pkg_get_name(causingpkg)); baddeps = alpm_list_add(baddeps, miss); } } @@ -309,7 +339,7 @@ static int dep_vercmp(const char *version1, pmdepmod_t mod, if(mod == PM_DEP_MOD_ANY) { equal = 1; } else { - int cmp = _alpm_versioncmp(version1, version2); + int cmp = alpm_pkg_vercmp(version1, version2); switch(mod) { case PM_DEP_MOD_EQ: equal = (cmp == 0); break; case PM_DEP_MOD_GE: equal = (cmp >= 0); break; @@ -356,7 +386,7 @@ int SYMEXPORT alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep) return(satisfy); } -pmdepend_t SYMEXPORT *alpm_splitdep(const char *depstring) +pmdepend_t *_alpm_splitdep(const char *depstring) { pmdepend_t *depend; char *ptr = NULL; @@ -365,9 +395,9 @@ pmdepend_t SYMEXPORT *alpm_splitdep(const char *depstring) if(depstring == NULL) { return(NULL); } - newstr = strdup(depstring); + STRDUP(newstr, depstring, RET_ERR(PM_ERR_MEMORY, NULL)); - MALLOC(depend, sizeof(pmdepend_t), return(NULL)); + CALLOC(depend, 1, sizeof(pmdepend_t), RET_ERR(PM_ERR_MEMORY, NULL)); /* Find a version comparator if one exists. If it does, set the type and * increment the ptr accordingly so we can copy the right strings. */ @@ -391,25 +421,36 @@ pmdepend_t SYMEXPORT *alpm_splitdep(const char *depstring) depend->mod = PM_DEP_MOD_GT; *ptr = '\0'; ptr += 1; - } else { - /* no version specified - copy in the name and return it */ + /* no version specified - copy the name and return it */ depend->mod = PM_DEP_MOD_ANY; - strncpy(depend->name, newstr, PKG_NAME_LEN); - depend->version[0] = '\0'; + STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL)); + depend->version = NULL; free(newstr); return(depend); } /* if we get here, we have a version comparator, copy the right parts * to the right places */ - strncpy(depend->name, newstr, PKG_NAME_LEN); - strncpy(depend->version, ptr, PKG_VERSION_LEN); + STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL)); + STRDUP(depend->version, ptr, RET_ERR(PM_ERR_MEMORY, NULL)); free(newstr); return(depend); } +pmdepend_t *_alpm_dep_dup(const pmdepend_t *dep) +{ + pmdepend_t *newdep; + CALLOC(newdep, 1, sizeof(pmdepend_t), RET_ERR(PM_ERR_MEMORY, NULL)); + + STRDUP(newdep->name, dep->name, RET_ERR(PM_ERR_MEMORY, NULL)); + STRDUP(newdep->version, dep->version, RET_ERR(PM_ERR_MEMORY, NULL)); + newdep->mod = dep->mod; + + return(newdep); +} + /* These parameters are messy. We check if this package, given a list of * targets and a db is safe to remove. We do NOT remove it if it is in the * target list, or if if the package was explictly installed and @@ -417,9 +458,9 @@ pmdepend_t SYMEXPORT *alpm_splitdep(const char *depstring) static int can_remove_package(pmdb_t *db, pmpkg_t *pkg, alpm_list_t *targets, int include_explicit) { - alpm_list_t *i, *requiredby; + alpm_list_t *i, *j; - if(_alpm_pkg_find(alpm_pkg_get_name(pkg), targets)) { + if(_alpm_pkg_find(targets, alpm_pkg_get_name(pkg))) { return(0); } @@ -439,15 +480,17 @@ static int can_remove_package(pmdb_t *db, pmpkg_t *pkg, alpm_list_t *targets, * if checkdeps detected it would break something */ /* see if other packages need it */ - requiredby = alpm_pkg_compute_requiredby(pkg); - for(i = requiredby; i; i = i->next) { - pmpkg_t *reqpkg = _alpm_db_get_pkgfromcache(db, i->data); - if(reqpkg && !_alpm_pkg_find(alpm_pkg_get_name(reqpkg), targets)) { - FREELIST(requiredby); - return(0); + for(i = _alpm_db_get_pkgcache(db); i; i = i->next) { + pmpkg_t *lpkg = i->data; + for(j = alpm_pkg_get_depends(lpkg); j; j = j->next) { + if(alpm_depcmp(pkg, j->data)) { + if(!_alpm_pkg_find(targets, lpkg->name)) { + return(0); + } + break; + } } } - FREELIST(requiredby); /* it's ok to remove */ return(1); @@ -523,7 +566,7 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg, for(i = deps; i; i = i->next) { int found = 0; pmdepmissing_t *miss = i->data; - pmdepend_t *missdep = &(miss->depend); + pmdepend_t *missdep = alpm_miss_get_dep(miss); pmpkg_t *sync = NULL; /* check if one of the packages in *list already satisfies this dependency */ @@ -548,13 +591,15 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg, if(!sync) { continue; } - found = alpm_depcmp(sync, missdep) && !_alpm_pkg_find(alpm_pkg_get_name(sync), remove); + found = alpm_depcmp(sync, missdep) && !_alpm_pkg_find(remove, alpm_pkg_get_name(sync)) + && !_alpm_pkg_find(*list, alpm_pkg_get_name(sync)); if(!found) { continue; } /* If package is in the ignorepkg list, ask before we pull it */ if(_alpm_pkg_should_ignore(sync)) { - pmpkg_t *dummypkg = _alpm_pkg_new(miss->target, NULL); + pmpkg_t *dummypkg = _alpm_pkg_new(); + STRDUP(dummypkg->name, miss->target, RET_ERR(PM_ERR_MEMORY, -1)); QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, dummypkg, sync, NULL, &found); _alpm_pkg_free(dummypkg); } @@ -570,12 +615,14 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg, continue; } found = alpm_depcmp(sync, missdep) && strcmp(sync->name, missdep->name) - && !_alpm_pkg_find(alpm_pkg_get_name(sync), remove); + && !_alpm_pkg_find(remove, alpm_pkg_get_name(sync)) + && !_alpm_pkg_find(*list, alpm_pkg_get_name(sync)); if(!found) { continue; } if(_alpm_pkg_should_ignore(sync)) { - pmpkg_t *dummypkg = _alpm_pkg_new(miss->target, NULL); + pmpkg_t *dummypkg = _alpm_pkg_new(); + STRDUP(dummypkg->name, miss->target, RET_ERR(PM_ERR_MEMORY, -1)); QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, dummypkg, sync, NULL, &found); _alpm_pkg_free(dummypkg); } @@ -611,7 +658,8 @@ int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg, _alpm_log(PM_LOG_DEBUG, "finished resolving dependencies\n"); - FREELIST(deps); + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free); + alpm_list_free(deps); return(0); @@ -627,7 +675,17 @@ const char SYMEXPORT *alpm_miss_get_target(const pmdepmissing_t *miss) /* Sanity checks */ ASSERT(miss != NULL, return(NULL)); - return miss->target; + return(miss->target); +} + +const char SYMEXPORT *alpm_miss_get_causingpkg(const pmdepmissing_t *miss) +{ + ALPM_LOG_FUNC; + + /* Sanity checks */ + ASSERT(miss != NULL, return(NULL)); + + return miss->causingpkg; } pmdepend_t SYMEXPORT *alpm_miss_get_dep(pmdepmissing_t *miss) @@ -637,7 +695,7 @@ pmdepend_t SYMEXPORT *alpm_miss_get_dep(pmdepmissing_t *miss) /* Sanity checks */ ASSERT(miss != NULL, return(NULL)); - return &(miss->depend); + return(miss->depend); } pmdepmod_t SYMEXPORT alpm_dep_get_mod(const pmdepend_t *dep) @@ -647,7 +705,7 @@ pmdepmod_t SYMEXPORT alpm_dep_get_mod(const pmdepend_t *dep) /* Sanity checks */ ASSERT(dep != NULL, return(-1)); - return dep->mod; + return(dep->mod); } const char SYMEXPORT *alpm_dep_get_name(const pmdepend_t *dep) @@ -657,7 +715,7 @@ const char SYMEXPORT *alpm_dep_get_name(const pmdepend_t *dep) /* Sanity checks */ ASSERT(dep != NULL, return(NULL)); - return dep->name; + return(dep->name); } const char SYMEXPORT *alpm_dep_get_version(const pmdepend_t *dep) @@ -667,7 +725,7 @@ const char SYMEXPORT *alpm_dep_get_version(const pmdepend_t *dep) /* Sanity checks */ ASSERT(dep != NULL, return(NULL)); - return dep->version; + return(dep->version); } /** Reverse of splitdep; make a dep string from a pmdepend_t struct. @@ -677,7 +735,7 @@ const char SYMEXPORT *alpm_dep_get_version(const pmdepend_t *dep) */ char SYMEXPORT *alpm_dep_get_string(const pmdepend_t *dep) { - char *opr, *str = NULL; + char *name, *opr, *ver, *str = NULL; size_t len; ALPM_LOG_FUNC; @@ -685,6 +743,12 @@ char SYMEXPORT *alpm_dep_get_string(const pmdepend_t *dep) /* Sanity checks */ ASSERT(dep != NULL, return(NULL)); + if(dep->name) { + name = dep->name; + } else { + name = ""; + } + switch(dep->mod) { case PM_DEP_MOD_ANY: opr = ""; @@ -709,11 +773,18 @@ char SYMEXPORT *alpm_dep_get_string(const pmdepend_t *dep) break; } + if(dep->version) { + ver = dep->version; + } else { + ver = ""; + } + /* we can always compute len and print the string like this because opr - * and ver will be empty when PM_DEP_MOD_ANY is the depend type */ - len = strlen(dep->name) + strlen(opr) + strlen(dep->version) + 1; + * and ver will be empty when PM_DEP_MOD_ANY is the depend type. the + * reassignments above also ensure we do not do a strlen(NULL). */ + len = strlen(name) + strlen(opr) + strlen(ver) + 1; MALLOC(str, len, RET_ERR(PM_ERR_MEMORY, NULL)); - snprintf(str, len, "%s%s%s", dep->name, opr, dep->version); + snprintf(str, len, "%s%s%s", name, opr, ver); return(str); } diff --git a/lib/libalpm/deps.h b/lib/libalpm/deps.h index 75cbb5bc..70badfd9 100644 --- a/lib/libalpm/deps.h +++ b/lib/libalpm/deps.h @@ -29,31 +29,29 @@ /* Dependency */ struct __pmdepend_t { pmdepmod_t mod; - char name[PKG_NAME_LEN]; - char version[PKG_VERSION_LEN]; + char *name; + char *version; }; /* Missing dependency */ struct __pmdepmissing_t { - char target[PKG_NAME_LEN]; - pmdepend_t depend; + char *target; + pmdepend_t *depend; + char *causingpkg; /* this is used in case of remove dependency error only */ }; -/* Graphs */ -struct __pmgraph_t { - int state; /* 0: untouched, -1: entered, other: leaving time */ - void *data; - struct __pmgraph_t *parent; /* where did we come from? */ - alpm_list_t *children; - alpm_list_t *childptr; /* points to a child in children list */ -}; - -pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepmod_t depmod, - const char *depname, const char *depversion); -alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode); +void _alpm_dep_free(pmdepend_t *dep); +pmdepend_t *_alpm_dep_dup(const pmdepend_t *dep); +pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepend_t *dep, + const char *causinpkg); +void _alpm_depmiss_free(pmdepmissing_t *miss); +alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, int reverse); void _alpm_recursedeps(pmdb_t *db, alpm_list_t *targs, int include_explicit); int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg, - alpm_list_t **list, alpm_list_t *remove, pmtrans_t *trans, alpm_list_t **data); + alpm_list_t **list, alpm_list_t *remove, pmtrans_t *trans, alpm_list_t + **data); +pmdepend_t *_alpm_splitdep(const char *depstring); +alpm_list_t *_alpm_find_dep_satisfiers(alpm_list_t *pkgs, pmdepend_t *dep); #endif /* _ALPM_DEPS_H */ diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c new file mode 100644 index 00000000..44acec70 --- /dev/null +++ b/lib/libalpm/dload.c @@ -0,0 +1,463 @@ +/* + * download.c + * + * Copyright (c) 2002-2008 by Judd Vinet <jvinet@zeroflux.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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> +/* the following two are needed on BSD for libfetch */ +#if defined(HAVE_SYS_SYSLIMITS_H) +#include <sys/syslimits.h> /* PATH_MAX */ +#endif +#if defined(HAVE_SYS_PARAM_H) +#include <sys/param.h> /* MAXHOSTNAMELEN */ +#endif + +#if defined(HAVE_LIBDOWNLOAD) +#include <download.h> +#elif defined(HAVE_LIBFETCH) +#include <fetch.h> +#define downloadFreeURL fetchFreeURL +#define downloadLastErrCode fetchLastErrCode +#define downloadLastErrString fetchLastErrString +#define downloadParseURL fetchParseURL +#define downloadTimeout fetchTimeout +#define downloadXGet fetchXGet +#endif + +/* libalpm */ +#include "dload.h" +#include "alpm_list.h" +#include "alpm.h" +#include "log.h" +#include "util.h" +#include "handle.h" + +static char *get_filename(const char *url) { + char *filename = strrchr(url, '/'); + if(filename != NULL) { + filename++; + } + return(filename); +} + +static char *get_destfile(const char *path, const char *filename) { + char *destfile; + /* len = localpath len + filename len + null */ + int len = strlen(path) + strlen(filename) + 1; + CALLOC(destfile, len, sizeof(char), RET_ERR(PM_ERR_MEMORY, NULL)); + snprintf(destfile, len, "%s%s", path, filename); + + return(destfile); +} + +static char *get_tempfile(const char *path, const char *filename) { + char *tempfile; + /* len = localpath len + filename len + '.part' len + null */ + int len = strlen(path) + strlen(filename) + 6; + CALLOC(tempfile, len, sizeof(char), RET_ERR(PM_ERR_MEMORY, NULL)); + snprintf(tempfile, len, "%s%s.part", path, filename); + + return(tempfile); +} + +#if defined(INTERNAL_DOWNLOAD) +/* Build a 'struct url' from an url. */ +static struct url *url_for_string(const char *url) +{ + struct url *ret = NULL; + ret = downloadParseURL(url); + if(!ret) { + _alpm_log(PM_LOG_ERROR, _("url '%s' is invalid\n"), url); + RET_ERR(PM_ERR_SERVER_BAD_URL, NULL); + } + + /* if no URL scheme specified, assume HTTP */ + if(strlen(ret->scheme) == 0) { + _alpm_log(PM_LOG_WARNING, _("url scheme not specified, assuming HTTP\n")); + strcpy(ret->scheme, SCHEME_HTTP); + } + /* add a user & password for anonymous FTP */ + if(strcmp(ret->scheme,SCHEME_FTP) == 0 && strlen(ret->user) == 0) { + strcpy(ret->user, "anonymous"); + strcpy(ret->pwd, "libalpm@guest"); + } + + return(ret); +} + +static int download_internal(const char *url, const char *localpath, + time_t mtimeold, time_t *mtimenew) { + FILE *dlf, *localf = NULL; + struct url_stat ust; + struct stat st; + int chk_resume = 0; + int dl_thisfile = 0; + char *tempfile, *destfile, *filename; + int ret = 0; + struct url *fileurl = url_for_string(url); + + if(!fileurl) { + return(-1); + } + + filename = get_filename(url); + if(!filename) { + return(-1); + } + destfile = get_destfile(localpath, filename); + tempfile = get_tempfile(localpath, filename); + + /* pass the raw filename for passing to the callback function */ + _alpm_log(PM_LOG_DEBUG, "using '%s' for download progress\n", filename); + + if(stat(tempfile, &st) == 0 && st.st_size > 0) { + _alpm_log(PM_LOG_DEBUG, "existing file found, using it\n"); + fileurl->offset = (off_t)st.st_size; + dl_thisfile = st.st_size; + localf = fopen(tempfile, "ab"); + chk_resume = 1; + } else { + fileurl->offset = (off_t)0; + dl_thisfile = 0; + } + + /* libdownload does not reset the error code, reset it in + * the case of previous errors */ + downloadLastErrCode = 0; + + /* 10s timeout - TODO make a config option */ + downloadTimeout = 10000; + + dlf = downloadXGet(fileurl, &ust, (handle->nopassiveftp ? "" : "p")); + + if(downloadLastErrCode != 0 || dlf == NULL) { + const char *host = _("disk"); + if(strcmp(SCHEME_FILE, fileurl->scheme) != 0) { + host = fileurl->host; + } + pm_errno = PM_ERR_LIBDOWNLOAD; + _alpm_log(PM_LOG_ERROR, _("failed retrieving file '%s' from %s : %s\n"), + filename, host, downloadLastErrString); + ret = -1; + goto cleanup; + } else { + _alpm_log(PM_LOG_DEBUG, "connected to %s successfully\n", fileurl->host); + } + + if(ust.mtime && mtimeold && ust.mtime == mtimeold) { + _alpm_log(PM_LOG_DEBUG, "mtimes are identical, skipping %s\n", filename); + ret = 1; + goto cleanup; + } + + if(ust.mtime && mtimenew) { + *mtimenew = ust.mtime; + } + + if(chk_resume && fileurl->offset == 0) { + _alpm_log(PM_LOG_WARNING, _("cannot resume download, starting over\n")); + if(localf != NULL) { + fclose(localf); + localf = NULL; + } + } + + if(localf == NULL) { + _alpm_rmrf(tempfile); + fileurl->offset = (off_t)0; + dl_thisfile = 0; + localf = fopen(tempfile, "wb"); + if(localf == NULL) { /* still null? */ + _alpm_log(PM_LOG_ERROR, _("cannot write to file '%s'\n"), tempfile); + ret = -1; + goto cleanup; + } + } + + /* Progress 0 - initialize */ + if(handle->dlcb) { + handle->dlcb(filename, 0, ust.size); + } + + int nread = 0; + char buffer[PM_DLBUF_LEN]; + while((nread = fread(buffer, 1, PM_DLBUF_LEN, dlf)) > 0) { + if(ferror(dlf)) { + pm_errno = PM_ERR_LIBDOWNLOAD; + _alpm_log(PM_LOG_ERROR, _("error downloading '%s': %s\n"), + filename, downloadLastErrString); + ret = -1; + goto cleanup; + } + + int nwritten = 0; + while(nwritten < nread) { + nwritten += fwrite(buffer, 1, (nread - nwritten), localf); + if(ferror(localf)) { + _alpm_log(PM_LOG_ERROR, _("error writing to file '%s': %s\n"), + destfile, strerror(errno)); + ret = -1; + goto cleanup; + } + } + dl_thisfile += nread; + + if(handle->dlcb) { + handle->dlcb(filename, dl_thisfile, ust.size); + } + } + /* probably safer to close the file descriptors now before renaming the file, + * for example to make sure the buffers are flushed. + */ + fclose(localf); + localf = NULL; + fclose(dlf); + dlf = NULL; + + rename(tempfile, destfile); + ret = 0; + +cleanup: + FREE(tempfile); + FREE(destfile); + if(localf != NULL) { + fclose(localf); + } + if(dlf != NULL) { + fclose(dlf); + } + downloadFreeURL(fileurl); + return(ret); +} +#endif + +static int download_external(const char *url, const char *localpath, + time_t mtimeold, time_t *mtimenew) { + int ret = 0; + int retval; + int usepart = 0; + char *ptr1, *ptr2; + char origCmd[PATH_MAX]; + char parsedCmd[PATH_MAX] = ""; + char cwd[PATH_MAX]; + char *destfile, *tempfile, *filename; + + if(!handle->xfercommand) { + RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1); + } + + filename = get_filename(url); + if(!filename) { + RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1); + } + destfile = get_destfile(localpath, filename); + tempfile = get_tempfile(localpath, filename); + + /* replace all occurrences of %o with fn.part */ + strncpy(origCmd, handle->xfercommand, sizeof(origCmd)); + ptr1 = origCmd; + while((ptr2 = strstr(ptr1, "%o"))) { + usepart = 1; + ptr2[0] = '\0'; + strcat(parsedCmd, ptr1); + strcat(parsedCmd, tempfile); + ptr1 = ptr2 + 2; + } + strcat(parsedCmd, ptr1); + /* replace all occurrences of %u with the download URL */ + strncpy(origCmd, parsedCmd, sizeof(origCmd)); + parsedCmd[0] = '\0'; + ptr1 = origCmd; + while((ptr2 = strstr(ptr1, "%u"))) { + ptr2[0] = '\0'; + strcat(parsedCmd, ptr1); + strcat(parsedCmd, url); + ptr1 = ptr2 + 2; + } + strcat(parsedCmd, ptr1); + /* cwd to the download directory */ + getcwd(cwd, PATH_MAX); + if(chdir(localpath)) { + _alpm_log(PM_LOG_WARNING, _("could not chdir to %s\n"), localpath); + pm_errno = PM_ERR_EXTERNAL_DOWNLOAD; + ret = -1; + goto cleanup; + } + /* execute the parsed command via /bin/sh -c */ + _alpm_log(PM_LOG_DEBUG, "running command: %s\n", parsedCmd); + retval = system(parsedCmd); + + if(retval == -1) { + _alpm_log(PM_LOG_WARNING, _("running XferCommand: fork failed!\n")); + pm_errno = PM_ERR_EXTERNAL_DOWNLOAD; + ret = -1; + } else if(retval != 0) { + /* download failed */ + _alpm_log(PM_LOG_DEBUG, "XferCommand command returned non-zero status " + "code (%d)\n", retval); + ret = -1; + } else { + /* download was successful */ + if(usepart) { + rename(tempfile, destfile); + } + ret = 0; + } + +cleanup: + chdir(cwd); + if(ret == -1) { + /* hack to let an user the time to cancel a download */ + sleep(2); + } + FREE(destfile); + FREE(tempfile); + + return(ret); +} + +static int download(const char *url, const char *localpath, + time_t mtimeold, time_t *mtimenew) { + int ret; + const char *proto = "file://"; + int len = strlen(proto); + if(strncmp(url, proto, len) == 0) { + /* we can simply grab an absolute path from the file:// url by starting + * our path at the char following the proto (the root '/') + */ + const char *sourcefile = url + len; + const char *filename = get_filename(url); + char *destfile = get_destfile(localpath, filename); + + ret = _alpm_copyfile(sourcefile, destfile); + FREE(destfile); + /* copyfile returns 1 on failure, we want to return -1 on failure */ + return(ret ? -1 : 0); + } + + /* We have a few things to take into account here. + * 1. If we have both internal/external available, choose based on + * whether xfercommand is populated. + * 2. If we only have external available, we should first check + * if a command was provided before we drop into download_external. + */ + if(handle->xfercommand == NULL) { +#if defined(INTERNAL_DOWNLOAD) + ret = download_internal(url, localpath, mtimeold, mtimenew); +#else + RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1); +#endif + } else { + ret = download_external(url, localpath, mtimeold, mtimenew); + } + return(ret); +} + +/* + * Download a single file + * - if mtimeold is non-NULL, then only download the file if it's different + * than mtimeold. + * - if *mtimenew is non-NULL, it will be filled with the mtime of the remote + * file. + * + * RETURN: 0 for successful download + * 1 if the mtimes are identical + * -1 on error + */ +int _alpm_download_single_file(const char *filename, + alpm_list_t *servers, const char *localpath, + time_t mtimeold, time_t *mtimenew) +{ + alpm_list_t *i; + int ret = -1; + + for(i = servers; i; i = i->next) { + const char *server = i->data; + char *fileurl = NULL; + int len; + + /* print server + filename into a buffer */ + len = strlen(server) + strlen(filename) + 2; + CALLOC(fileurl, len, sizeof(char), RET_ERR(PM_ERR_MEMORY, -1)); + snprintf(fileurl, len, "%s/%s", server, filename); + + ret = download(fileurl, localpath, mtimeold, mtimenew); + FREE(fileurl); + if(ret != -1) { + break; + } + } + + return(ret); +} + +int _alpm_download_files(alpm_list_t *files, + alpm_list_t *servers, const char *localpath) +{ + int ret = 0; + alpm_list_t *lp; + + for(lp = files; lp; lp = lp->next) { + char *filename = lp->data; + if(_alpm_download_single_file(filename, servers, + localpath, 0, NULL) == -1) { + ret++; + } + } + + return(ret); +} + +/** Fetch a remote pkg. + * @param url URL of the package to download + * @return the downloaded filepath on success, NULL on error + * @addtogroup alpm_misc + */ +char SYMEXPORT *alpm_fetch_pkgurl(const char *url) +{ + char *filename, *filepath; + const char *cachedir; + int ret; + + ALPM_LOG_FUNC; + + filename = get_filename(url); + + /* find a valid cache dir to download to */ + cachedir = _alpm_filecache_setup(); + + /* download the file */ + ret = download(url, cachedir, 0, NULL); + if(ret == -1) { + _alpm_log(PM_LOG_WARNING, _("failed to download %s\n"), url); + return(NULL); + } + _alpm_log(PM_LOG_DEBUG, "successfully downloaded %s\n", url); + + /* we should be able to find the file the second time around */ + filepath = _alpm_filecache_find(filename); + return(filepath); +} + +/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/error.h b/lib/libalpm/dload.h index e417195f..eb642522 100644 --- a/lib/libalpm/error.h +++ b/lib/libalpm/dload.h @@ -1,7 +1,7 @@ /* - * error.h + * dload.h * - * Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org> + * Copyright (c) 2002-2008 by Judd Vinet <jvinet@zeroflux.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 @@ -16,13 +16,23 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _ALPM_ERROR_H -#define _ALPM_ERROR_H +#ifndef _ALPM_DLOAD_H +#define _ALPM_DLOAD_H -#define RET_ERR(err, ret) do { pm_errno = (err); \ - _alpm_log(PM_LOG_DEBUG, "returning error %d from %s : %s\n", err, __func__, alpm_strerrorlast()); \ - return(ret); } while(0) +#include "alpm_list.h" +#include "alpm.h" -#endif /* _ALPM_ERROR_H */ +#include <time.h> + +#define PM_DLBUF_LEN (1024 * 10) + +int _alpm_download_single_file(const char *filename, + alpm_list_t *servers, const char *localpath, + time_t mtimeold, time_t *mtimenew); + +int _alpm_download_files(alpm_list_t *files, + alpm_list_t *servers, const char *localpath); + +#endif /* _ALPM_DLOAD_H */ /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c index a68340ad..05caf8ec 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -1,10 +1,7 @@ /* * error.c * - * Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org> - * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> - * Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> - * Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org> + * Copyright (c) 2002-2008 by Judd Vinet <jvinet@zeroflux.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 @@ -22,12 +19,28 @@ #include "config.h" +/* TODO: needed for the libfetch stuff, unfortunately- we should kill it */ +#include <stdio.h> +#include <limits.h> +/* the following two are needed on BSD for libfetch */ +#if defined(HAVE_SYS_SYSLIMITS_H) +#include <sys/syslimits.h> /* PATH_MAX */ +#endif +#if defined(HAVE_SYS_PARAM_H) +#include <sys/param.h> /* MAXHOSTNAMELEN */ +#endif + +#if defined(HAVE_LIBDOWNLOAD) +#include <download.h> /* downloadLastErrString */ +#elif defined(HAVE_LIBFETCH) +#include <fetch.h> /* fetchLastErrString */ +#define downloadLastErrString fetchLastErrString +#endif + /* libalpm */ -#include "error.h" #include "util.h" #include "alpm.h" -/* TODO does this really need a file all on its own? */ const char SYMEXPORT *alpm_strerrorlast(void) { return alpm_strerror(pm_errno); @@ -74,13 +87,6 @@ const char SYMEXPORT *alpm_strerror(int err) /* Servers */ case PM_ERR_SERVER_BAD_URL: return _("invalid url for server"); - /* Configuration */ - case PM_ERR_OPT_LOGFILE: - case PM_ERR_OPT_DBPATH: - case PM_ERR_OPT_LOCALDB: - case PM_ERR_OPT_SYNCDB: - case PM_ERR_OPT_USESYSLOG: - return _("could not set parameter"); /* Transactions */ case PM_ERR_TRANS_NOT_NULL: return _("transaction already initialized"); @@ -109,21 +115,17 @@ const char SYMEXPORT *alpm_strerror(int err) return _("cannot open package file"); case PM_ERR_PKG_LOAD: return _("cannot load package data"); - case PM_ERR_PKG_INSTALLED: - return _("package already installed"); case PM_ERR_PKG_CANT_FRESH: return _("package not installed or lesser version"); case PM_ERR_PKG_CANT_REMOVE: return _("cannot remove all files for package"); case PM_ERR_PKG_INVALID_NAME: - return _("package name is not valid"); - case PM_ERR_PKG_CORRUPTED: - return _("corrupted package"); + return _("package filename is not valid"); case PM_ERR_PKG_REPO_NOT_FOUND: return _("no such repository"); /* Deltas */ - case PM_ERR_DLT_CORRUPTED: - return _("corrupted delta"); + case PM_ERR_DLT_INVALID: + return _("invalid or corrupted delta"); case PM_ERR_DLT_PATCHFAILED: return _("delta patch failed"); /* Groups */ @@ -141,16 +143,26 @@ const char SYMEXPORT *alpm_strerror(int err) return _("user aborted the operation"); case PM_ERR_INTERNAL_ERROR: return _("internal error"); - case PM_ERR_LIBARCHIVE_ERROR: - return _("libarchive error"); case PM_ERR_PKG_HOLD: /* TODO wow this is not descriptive at all... what does this mean? */ return _("not confirmed"); case PM_ERR_INVALID_REGEX: return _("invalid regular expression"); - /* Downloading */ - case PM_ERR_CONNECT_FAILED: - return _("connection to remote host failed"); + /* Errors from external libraries- our own wrapper error */ + case PM_ERR_LIBARCHIVE: + /* it would be nice to use archive_error_string() here, but that + * requires the archive struct, so we can't. Just use a generic + * error string instead. */ + return _("libarchive error"); + case PM_ERR_LIBDOWNLOAD: +#if defined(INTERNAL_DOWNLOAD) + return downloadLastErrString; +#else + /* obviously shouldn't get here... */ + return _("download library error"); +#endif + case PM_ERR_EXTERNAL_DOWNLOAD: + return _("error invoking external downloader"); /* Unknown error! */ default: return _("unexpected error"); diff --git a/lib/libalpm/graph.h b/lib/libalpm/graph.h new file mode 100644 index 00000000..3078e25f --- /dev/null +++ b/lib/libalpm/graph.h @@ -0,0 +1,56 @@ +/* + * graph.h - helpful graph structure and setup/teardown methods + * + * Copyright (c) 2002-2008 by Judd Vinet <jvinet@zeroflux.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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "alpm_list.h" +#include "util.h" /* MALLOC() */ +#include "alpm.h" + +struct __pmgraph_t { + char state; /* 0: untouched, -1: entered, other: leaving time */ + void *data; + unsigned long int weight; /* weight of the node */ + struct __pmgraph_t *parent; /* where did we come from? */ + alpm_list_t *children; + alpm_list_t *childptr; /* points to a child in children list */ +}; +typedef struct __pmgraph_t pmgraph_t; + +static pmgraph_t *_alpm_graph_new(void) +{ + pmgraph_t *graph = NULL; + + MALLOC(graph, sizeof(pmgraph_t), RET_ERR(PM_ERR_MEMORY, NULL)); + + if(graph) { + graph->state = 0; + graph->data = NULL; + graph->parent = NULL; + graph->children = NULL; + graph->childptr = NULL; + } + return(graph); +} + +static void _alpm_graph_free(void *data) +{ + pmgraph_t *graph = data; + alpm_list_free(graph->children); + free(graph); +} + diff --git a/lib/libalpm/group.c b/lib/libalpm/group.c index 050bcbd5..3e080a58 100644 --- a/lib/libalpm/group.c +++ b/lib/libalpm/group.c @@ -27,17 +27,17 @@ #include "group.h" #include "alpm_list.h" #include "util.h" -#include "error.h" #include "log.h" #include "alpm.h" -pmgrp_t *_alpm_grp_new() +pmgrp_t *_alpm_grp_new(const char *name) { pmgrp_t* grp; ALPM_LOG_FUNC; CALLOC(grp, 1, sizeof(pmgrp_t), RET_ERR(PM_ERR_MEMORY, NULL)); + STRDUP(grp->name, name, RET_ERR(PM_ERR_MEMORY, NULL)); return(grp); } @@ -50,20 +50,12 @@ void _alpm_grp_free(pmgrp_t *grp) return; } - FREELIST(grp->packages); + FREE(grp->name); + /* do NOT free the contents of the list, just the nodes */ + alpm_list_free(grp->packages); FREE(grp); } -/* Helper function for sorting groups - */ -int _alpm_grp_cmp(const void *g1, const void *g2) -{ - pmgrp_t *grp1 = (pmgrp_t *)g1; - pmgrp_t *grp2 = (pmgrp_t *)g2; - - return(strcmp(grp1->name, grp2->name)); -} - const char SYMEXPORT *alpm_grp_get_name(const pmgrp_t *grp) { ALPM_LOG_FUNC; @@ -74,7 +66,7 @@ const char SYMEXPORT *alpm_grp_get_name(const pmgrp_t *grp) return grp->name; } -const alpm_list_t SYMEXPORT *alpm_grp_get_pkgs(const pmgrp_t *grp) +alpm_list_t SYMEXPORT *alpm_grp_get_pkgs(const pmgrp_t *grp) { ALPM_LOG_FUNC; diff --git a/lib/libalpm/group.h b/lib/libalpm/group.h index 88fc8b32..e261260c 100644 --- a/lib/libalpm/group.h +++ b/lib/libalpm/group.h @@ -19,19 +19,17 @@ #ifndef _ALPM_GROUP_H #define _ALPM_GROUP_H -/* Groups */ -#define GRP_NAME_LEN 256 - #include "alpm.h" struct __pmgrp_t { - char name[GRP_NAME_LEN]; - alpm_list_t *packages; /* List of strings */ + /** group name */ + char *name; + /** list of pmpkg_t packages */ + alpm_list_t *packages; }; -pmgrp_t *_alpm_grp_new(void); +pmgrp_t *_alpm_grp_new(const char *name); void _alpm_grp_free(pmgrp_t *grp); -int _alpm_grp_cmp(const void *g1, const void *g2); #endif /* _ALPM_GROUP_H */ diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index 36822285..c01dd551 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -23,7 +23,6 @@ #include <stdlib.h> #include <string.h> -#include <unistd.h> #include <limits.h> #include <sys/types.h> #include <syslog.h> @@ -36,10 +35,8 @@ #include "alpm_list.h" #include "util.h" #include "log.h" -#include "error.h" #include "trans.h" #include "alpm.h" -#include "server.h" /* global var for handle (private to libalpm) */ pmhandle_t *handle = NULL; @@ -55,8 +52,6 @@ pmhandle_t *_alpm_handle_new() handle->lckfd = -1; handle->logstream = NULL; - /* see if we're root or not */ - handle->uid = geteuid(); handle->root = NULL; handle->dbpath = NULL; handle->cachedirs = NULL; @@ -386,7 +381,7 @@ void SYMEXPORT alpm_option_set_cachedirs(alpm_list_t *cachedirs) int SYMEXPORT alpm_option_remove_cachedir(const char *cachedir) { - void *vdata = NULL; + char *vdata = NULL; char *newcachedir; size_t cachedirlen; /* verify cachedir ends in a '/' */ @@ -397,8 +392,7 @@ int SYMEXPORT alpm_option_remove_cachedir(const char *cachedir) newcachedir = calloc(cachedirlen + 1, sizeof(char)); strncpy(newcachedir, cachedir, cachedirlen); newcachedir[cachedirlen-1] = '/'; - handle->cachedirs = alpm_list_remove(handle->cachedirs, newcachedir, - _alpm_str_cmp, &vdata); + handle->cachedirs = alpm_list_remove_str(handle->cachedirs, newcachedir, &vdata); FREE(newcachedir); if(vdata != NULL) { FREE(vdata); @@ -451,9 +445,8 @@ void SYMEXPORT alpm_option_set_noupgrades(alpm_list_t *noupgrade) int SYMEXPORT alpm_option_remove_noupgrade(const char *pkg) { - void *vdata = NULL; - handle->noupgrade = alpm_list_remove(handle->noupgrade, pkg, - _alpm_str_cmp, &vdata); + char *vdata = NULL; + handle->noupgrade = alpm_list_remove_str(handle->noupgrade, pkg, &vdata); if(vdata != NULL) { FREE(vdata); return(1); @@ -474,9 +467,8 @@ void SYMEXPORT alpm_option_set_noextracts(alpm_list_t *noextract) int SYMEXPORT alpm_option_remove_noextract(const char *pkg) { - void *vdata = NULL; - handle->noextract = alpm_list_remove(handle->noextract, pkg, - _alpm_str_cmp, &vdata); + char *vdata = NULL; + handle->noextract = alpm_list_remove_str(handle->noextract, pkg, &vdata); if(vdata != NULL) { FREE(vdata); return(1); @@ -497,9 +489,8 @@ void SYMEXPORT alpm_option_set_ignorepkgs(alpm_list_t *ignorepkgs) int SYMEXPORT alpm_option_remove_ignorepkg(const char *pkg) { - void *vdata = NULL; - handle->ignorepkg = alpm_list_remove(handle->ignorepkg, pkg, - _alpm_str_cmp, &vdata); + char *vdata = NULL; + handle->ignorepkg = alpm_list_remove_str(handle->ignorepkg, pkg, &vdata); if(vdata != NULL) { FREE(vdata); return(1); @@ -520,9 +511,8 @@ void SYMEXPORT alpm_option_set_holdpkgs(alpm_list_t *holdpkgs) int SYMEXPORT alpm_option_remove_holdpkg(const char *pkg) { - void *vdata = NULL; - handle->holdpkg = alpm_list_remove(handle->holdpkg, pkg, - _alpm_str_cmp, &vdata); + char *vdata = NULL; + handle->holdpkg = alpm_list_remove_str(handle->holdpkg, pkg, &vdata); if(vdata != NULL) { FREE(vdata); return(1); @@ -543,9 +533,8 @@ void SYMEXPORT alpm_option_set_ignoregrps(alpm_list_t *ignoregrps) int SYMEXPORT alpm_option_remove_ignoregrp(const char *grp) { - void *vdata = NULL; - handle->ignoregrp = alpm_list_remove(handle->ignoregrp, grp, - _alpm_str_cmp, &vdata); + char *vdata = NULL; + handle->ignoregrp = alpm_list_remove_str(handle->ignoregrp, grp, &vdata); if(vdata != NULL) { FREE(vdata); return(1); diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index 5051917e..9c537b14 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -30,7 +30,6 @@ typedef struct _pmhandle_t { /* internal usage */ - uid_t uid; /* current UID */ /* TODO is this used? */ pmdb_t *db_local; /* local db pointer */ alpm_list_t *dbs_sync; /* List of (pmdb_t *) */ FILE *logstream; /* log file stream pointer */ @@ -50,7 +49,7 @@ typedef struct _pmhandle_t { /* package lists */ alpm_list_t *noupgrade; /* List of packages NOT to be upgraded */ - alpm_list_t *noextract; /* List of packages NOT to extract */ /*TODO is this used?*/ + alpm_list_t *noextract; /* List of files NOT to extract */ alpm_list_t *ignorepkg; /* List of packages to ignore */ alpm_list_t *holdpkg; /* List of packages which 'hold' pacman */ alpm_list_t *ignoregrp; /* List of groups to ignore */ diff --git a/lib/libalpm/log.c b/lib/libalpm/log.c index 4445f935..3ba5042c 100644 --- a/lib/libalpm/log.c +++ b/lib/libalpm/log.c @@ -30,7 +30,6 @@ #include "log.h" #include "handle.h" #include "util.h" -#include "error.h" #include "alpm.h" /** \addtogroup alpm_log Logging Functions diff --git a/lib/libalpm/md5.c b/lib/libalpm/md5.c index 4c903895..1923242a 100644 --- a/lib/libalpm/md5.c +++ b/lib/libalpm/md5.c @@ -3,14 +3,15 @@ * * Copyright (C) 2006-2007 Christophe Devine * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License, version 2.1 as published by the Free Software Foundation. + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This library is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see @@ -25,8 +26,9 @@ * Pacman Notes: * * Taken from the XySSL project at www.xyssl.org under terms of the - * LGPL. This is from version 0.7 of the library, and has been modified + * GPL. This is from version 0.9 of the library, and has been modified * as following, which may be helpful for future updates: + * * remove "xyssl/config.h" include * * change include from "xyssl/md5.h" to "md5.h" * * removal of HMAC code * * removal of SELF_TEST code @@ -35,12 +37,9 @@ * int md5_file( char *path, unsigned char *output ) * to * int md5_file( const char *path, unsigned char *output ) + * * various static/inline changes */ -#ifndef _CRT_SECURE_NO_DEPRECATE -#define _CRT_SECURE_NO_DEPRECATE 1 -#endif - #include <string.h> #include <stdio.h> @@ -49,8 +48,8 @@ /* * 32-bit integer manipulation macros (little endian) */ -#ifndef GET_UINT32_LE -#define GET_UINT32_LE(n,b,i) \ +#ifndef GET_ULONG_LE +#define GET_ULONG_LE(n,b,i) \ { \ (n) = ( (unsigned long) (b)[(i) ] ) \ | ( (unsigned long) (b)[(i) + 1] << 8 ) \ @@ -59,8 +58,8 @@ } #endif -#ifndef PUT_UINT32_LE -#define PUT_UINT32_LE(n,b,i) \ +#ifndef PUT_ULONG_LE +#define PUT_ULONG_LE(n,b,i) \ { \ (b)[(i) ] = (unsigned char) ( (n) ); \ (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ @@ -87,22 +86,22 @@ static inline void md5_process( md5_context *ctx, unsigned char data[64] ) { unsigned long X[16], A, B, C, D; - GET_UINT32_LE( X[ 0], data, 0 ); - GET_UINT32_LE( X[ 1], data, 4 ); - GET_UINT32_LE( X[ 2], data, 8 ); - GET_UINT32_LE( X[ 3], data, 12 ); - GET_UINT32_LE( X[ 4], data, 16 ); - GET_UINT32_LE( X[ 5], data, 20 ); - GET_UINT32_LE( X[ 6], data, 24 ); - GET_UINT32_LE( X[ 7], data, 28 ); - GET_UINT32_LE( X[ 8], data, 32 ); - GET_UINT32_LE( X[ 9], data, 36 ); - GET_UINT32_LE( X[10], data, 40 ); - GET_UINT32_LE( X[11], data, 44 ); - GET_UINT32_LE( X[12], data, 48 ); - GET_UINT32_LE( X[13], data, 52 ); - GET_UINT32_LE( X[14], data, 56 ); - GET_UINT32_LE( X[15], data, 60 ); + GET_ULONG_LE( X[ 0], data, 0 ); + GET_ULONG_LE( X[ 1], data, 4 ); + GET_ULONG_LE( X[ 2], data, 8 ); + GET_ULONG_LE( X[ 3], data, 12 ); + GET_ULONG_LE( X[ 4], data, 16 ); + GET_ULONG_LE( X[ 5], data, 20 ); + GET_ULONG_LE( X[ 6], data, 24 ); + GET_ULONG_LE( X[ 7], data, 28 ); + GET_ULONG_LE( X[ 8], data, 32 ); + GET_ULONG_LE( X[ 9], data, 36 ); + GET_ULONG_LE( X[10], data, 40 ); + GET_ULONG_LE( X[11], data, 44 ); + GET_ULONG_LE( X[12], data, 48 ); + GET_ULONG_LE( X[13], data, 52 ); + GET_ULONG_LE( X[14], data, 56 ); + GET_ULONG_LE( X[15], data, 60 ); #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) @@ -250,7 +249,7 @@ static inline void md5_update( md5_context *ctx, unsigned char *input, int ilen } } -static unsigned char md5_padding[64] = +static const unsigned char md5_padding[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -261,7 +260,7 @@ static unsigned char md5_padding[64] = /* * MD5 final digest */ -static inline void md5_finish( md5_context *ctx, unsigned char *output ) +static inline void md5_finish( md5_context *ctx, unsigned char output[16] ) { unsigned long last, padn; unsigned long high, low; @@ -271,8 +270,8 @@ static inline void md5_finish( md5_context *ctx, unsigned char *output ) | ( ctx->total[1] << 3 ); low = ( ctx->total[0] << 3 ); - PUT_UINT32_LE( low, msglen, 0 ); - PUT_UINT32_LE( high, msglen, 4 ); + PUT_ULONG_LE( low, msglen, 0 ); + PUT_ULONG_LE( high, msglen, 4 ); last = ctx->total[0] & 0x3F; padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); @@ -280,17 +279,16 @@ static inline void md5_finish( md5_context *ctx, unsigned char *output ) md5_update( ctx, (unsigned char *) md5_padding, padn ); md5_update( ctx, msglen, 8 ); - PUT_UINT32_LE( ctx->state[0], output, 0 ); - PUT_UINT32_LE( ctx->state[1], output, 4 ); - PUT_UINT32_LE( ctx->state[2], output, 8 ); - PUT_UINT32_LE( ctx->state[3], output, 12 ); + PUT_ULONG_LE( ctx->state[0], output, 0 ); + PUT_ULONG_LE( ctx->state[1], output, 4 ); + PUT_ULONG_LE( ctx->state[2], output, 8 ); + PUT_ULONG_LE( ctx->state[3], output, 12 ); } /* - * Output = MD5( input buffer ) + * output = MD5( input buffer ) */ -void md5( unsigned char *input, int ilen, - unsigned char *output ) +void md5( unsigned char *input, int ilen, unsigned char output[16] ) { md5_context ctx; @@ -302,9 +300,9 @@ void md5( unsigned char *input, int ilen, } /* - * Output = MD5( file contents ) + * output = MD5( file contents ) */ -int md5_file( const char *path, unsigned char *output ) +int md5_file( const char *path, unsigned char output[16] ) { FILE *f; size_t n; diff --git a/lib/libalpm/md5.h b/lib/libalpm/md5.h index d206e463..25b4ff58 100644 --- a/lib/libalpm/md5.h +++ b/lib/libalpm/md5.h @@ -3,14 +3,15 @@ * * Copyright (C) 2006-2007 Christophe Devine * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License, version 2.1 as published by the Free Software Foundation. + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This library is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see @@ -20,12 +21,7 @@ #ifndef _MD5_H #define _MD5_H -#ifdef __cplusplus -extern "C" { -#endif - /** - * \internal * \brief MD5 context structure */ typedef struct @@ -37,18 +33,15 @@ typedef struct md5_context; /** - * \internal * \brief Output = MD5( input buffer ) * * \param input buffer holding the data * \param ilen length of the input data * \param output MD5 checksum result */ -void md5( unsigned char *input, int ilen, - unsigned char *output ); +void md5( unsigned char *input, int ilen, unsigned char output[16] ); /** - * \internal * \brief Output = MD5( file contents ) * * \param path input file name @@ -57,10 +50,6 @@ void md5( unsigned char *input, int ilen, * \return 0 if successful, 1 if fopen failed, * or 2 if fread failed */ -int md5_file( const char *path, unsigned char *output ); - -#ifdef __cplusplus -} -#endif +int md5_file( const char *path, unsigned char output[16] ); #endif /* md5.h */ diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index 794a2f7d..07b5fa38 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -31,7 +31,6 @@ #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> -#include <locale.h> /* setlocale */ /* libarchive */ #include <archive.h> @@ -42,7 +41,6 @@ #include "alpm_list.h" #include "log.h" #include "util.h" -#include "error.h" #include "db.h" #include "cache.h" #include "delta.h" @@ -54,42 +52,13 @@ * @{ */ -/** Create a package from a file. - * If full is false, the archive is read only until all necessary - * metadata is found. If it is true, the entire archive is read, which - * serves as a verfication of integrity and the filelist can be created. - * @param filename location of the package tarball - * @param full whether to stop the load after metadata is read or continue - * through the full archive - * @param pkg address of the package pointer - * @return 0 on success, -1 on error (pm_errno is set accordingly) - */ -int SYMEXPORT alpm_pkg_load(const char *filename, unsigned short full, - pmpkg_t **pkg) -{ - _alpm_log(PM_LOG_FUNCTION, "enter alpm_pkg_load\n"); - - /* Sanity checks */ - ASSERT(filename != NULL && strlen(filename) != 0, - RET_ERR(PM_ERR_WRONG_ARGS, -1)); - ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1)); - - *pkg = _alpm_pkg_load(filename, full); - if(*pkg == NULL) { - /* pm_errno is set by pkg_load */ - return(-1); - } - - return(0); -} - /** Free a package. * @param pkg package pointer to free * @return 0 on success, -1 on error (pm_errno is set accordingly) */ int SYMEXPORT alpm_pkg_free(pmpkg_t *pkg) { - _alpm_log(PM_LOG_FUNCTION, "enter alpm_pkg_free\n"); + ALPM_LOG_FUNC; ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1)); @@ -108,8 +77,7 @@ int SYMEXPORT alpm_pkg_free(pmpkg_t *pkg) int SYMEXPORT alpm_pkg_checkmd5sum(pmpkg_t *pkg) { char *fpath; - char *md5sum = NULL; - int retval = 0; + int retval; ALPM_LOG_FUNC; @@ -119,44 +87,19 @@ int SYMEXPORT alpm_pkg_checkmd5sum(pmpkg_t *pkg) ASSERT(pkg->origin_data.db != handle->db_local, RET_ERR(PM_ERR_PKG_INVALID, -1)); fpath = _alpm_filecache_find(alpm_pkg_get_filename(pkg)); - md5sum = alpm_get_md5sum(fpath); - if(md5sum == NULL) { - _alpm_log(PM_LOG_ERROR, _("could not get md5sum for package %s-%s\n"), - alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); - pm_errno = PM_ERR_NOT_A_FILE; + retval = _alpm_test_md5sum(fpath, alpm_pkg_get_md5sum(pkg)); + + if(retval == 0) { + return(0); + } else if (retval == 1) { + pm_errno = PM_ERR_PKG_INVALID; retval = -1; - } else { - if(strcmp(md5sum, alpm_pkg_get_md5sum(pkg)) == 0) { - _alpm_log(PM_LOG_DEBUG, "md5sums for package %s-%s match\n", - alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); - } else { - _alpm_log(PM_LOG_ERROR, _("md5sums do not match for package %s-%s\n"), - alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); - pm_errno = PM_ERR_PKG_INVALID; - retval = -1; - } } - FREE(fpath); - FREE(md5sum); - return(retval); } -/** Compare versions. - * @param ver1 first version - * @param ver2 secont version - * @return postive, 0 or negative if ver1 is less, equal or more - * than ver2, respectively. - */ -int SYMEXPORT alpm_pkg_vercmp(const char *ver1, const char *ver2) -{ - ALPM_LOG_FUNC; - - return(_alpm_versioncmp(ver1, ver2)); -} - const char SYMEXPORT *alpm_pkg_get_filename(pmpkg_t *pkg) { ALPM_LOG_FUNC; @@ -169,45 +112,18 @@ const char SYMEXPORT *alpm_pkg_get_filename(pmpkg_t *pkg) _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_DESC); } - if(!strlen(pkg->filename)) { - /* construct the file name, it's not in the desc file */ - if(pkg->arch && strlen(pkg->arch) > 0) { - snprintf(pkg->filename, PKG_FILENAME_LEN, "%s-%s-%s" PKGEXT, - pkg->name, pkg->version, pkg->arch); - } else { - snprintf(pkg->filename, PKG_FILENAME_LEN, "%s-%s" PKGEXT, - pkg->name, pkg->version); - } - } - return pkg->filename; } const char SYMEXPORT *alpm_pkg_get_name(pmpkg_t *pkg) { - ALPM_LOG_FUNC; - - /* Sanity checks */ - ASSERT(handle != NULL, return(NULL)); ASSERT(pkg != NULL, return(NULL)); - - if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_BASE)) { - _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_BASE); - } return pkg->name; } const char SYMEXPORT *alpm_pkg_get_version(pmpkg_t *pkg) { - ALPM_LOG_FUNC; - - /* Sanity checks */ - ASSERT(handle != NULL, return(NULL)); ASSERT(pkg != NULL, return(NULL)); - - if(pkg->origin == PKG_FROM_CACHE && !(pkg->infolevel & INFRQ_BASE)) { - _alpm_db_read(pkg->origin_data.db, pkg, INFRQ_BASE); - } return pkg->version; } @@ -523,7 +439,7 @@ void SYMEXPORT *alpm_pkg_changelog_open(pmpkg_t *pkg) int ret = ARCHIVE_OK; if((archive = archive_read_new()) == NULL) { - RET_ERR(PM_ERR_LIBARCHIVE_ERROR, NULL); + RET_ERR(PM_ERR_LIBARCHIVE, NULL); } archive_read_support_compression_all(archive); @@ -652,106 +568,158 @@ alpm_list_t SYMEXPORT *alpm_pkg_compute_requiredby(pmpkg_t *pkg) /** @} */ -/* this function was taken from rpm 4.0.4 and rewritten */ -int _alpm_versioncmp(const char *a, const char *b) +/** Compare two version strings and determine which one is 'newer'. + * Returns a value comparable to the way strcmp works. Returns 1 + * if a is newer than b, 0 if a and b are the same version, or -1 + * if b is newer than a. + * + * This function has been adopted from the rpmvercmp function located + * at lib/rpmvercmp.c, and was most recently updated against rpm + * version 4.4.2.3. Small modifications have been made to make it more + * consistent with the libalpm coding style. + */ +int SYMEXPORT alpm_pkg_vercmp(const char *a, const char *b) { - char str1[64], str2[64]; + char oldch1, oldch2; + char *str1, *str2; char *ptr1, *ptr2; char *one, *two; - char *rel1 = NULL, *rel2 = NULL; - char oldch1, oldch2; - int is1num, is2num; int rc; + int isnum; + int ret = 0; ALPM_LOG_FUNC; - if(!strcmp(a,b)) { - return(0); + /* libalpm added code. ensure our strings are not null */ + if(!a) { + if(!b) return(0); + return(-1); } + if(!b) return(1); - strncpy(str1, a, 64); - str1[63] = 0; - strncpy(str2, b, 64); - str2[63] = 0; + /* easy comparison to see if versions are identical */ + if(strcmp(a, b) == 0) return(0); - /* lose the release number */ - for(one = str1; *one && *one != '-'; one++); - if(one) { - *one = '\0'; - rel1 = ++one; - } - for(two = str2; *two && *two != '-'; two++); - if(two) { - *two = '\0'; - rel2 = ++two; - } + str1 = strdup(a); + str2 = strdup(b); one = str1; two = str2; - while(*one || *two) { + /* loop through each version segment of str1 and str2 and compare them */ + while(*one && *two) { while(*one && !isalnum((int)*one)) one++; while(*two && !isalnum((int)*two)) two++; + /* If we ran to the end of either, we are finished with the loop */ + if(!(*one && *two)) break; + ptr1 = one; ptr2 = two; - /* find the next segment for each string */ + /* grab first completely alpha or completely numeric segment */ + /* leave one and two pointing to the start of the alpha or numeric */ + /* segment and walk ptr1 and ptr2 to end of segment */ if(isdigit((int)*ptr1)) { - is1num = 1; while(*ptr1 && isdigit((int)*ptr1)) ptr1++; - } else { - is1num = 0; - while(*ptr1 && isalpha((int)*ptr1)) ptr1++; - } - if(isdigit((int)*ptr2)) { - is2num = 1; while(*ptr2 && isdigit((int)*ptr2)) ptr2++; + isnum = 1; } else { - is2num = 0; + while(*ptr1 && isalpha((int)*ptr1)) ptr1++; while(*ptr2 && isalpha((int)*ptr2)) ptr2++; + isnum = 0; } + /* save character at the end of the alpha or numeric segment */ + /* so that they can be restored after the comparison */ oldch1 = *ptr1; *ptr1 = '\0'; oldch2 = *ptr2; *ptr2 = '\0'; - /* see if we ran out of segments on one string */ - if(one == ptr1 && two != ptr2) { - return(is2num ? -1 : 1); + /* this cannot happen, as we previously tested to make sure that */ + /* the first string has a non-null segment */ + if (one == ptr1) { + ret = -1; /* arbitrary */ + goto cleanup; } - if(one != ptr1 && two == ptr2) { - return(is1num ? 1 : -1); + + /* take care of the case where the two version segments are */ + /* different types: one numeric, the other alpha (i.e. empty) */ + /* numeric segments are always newer than alpha segments */ + /* XXX See patch #60884 (and details) from bugzilla #50977. */ + if (two == ptr2) { + ret = isnum ? 1 : -1; + goto cleanup; } - /* see if we have a type mismatch (ie, one is alpha and one is digits) */ - if(is1num && !is2num) return(1); - if(!is1num && is2num) return(-1); + if (isnum) { + /* this used to be done by converting the digit segments */ + /* to ints using atoi() - it's changed because long */ + /* digit segments can overflow an int - this should fix that. */ - if(is1num) while(*one == '0') one++; - if(is2num) while(*two == '0') two++; + /* throw away any leading zeros - it's a number, right? */ + while (*one == '0') one++; + while (*two == '0') two++; + + /* whichever number has more digits wins */ + if (strlen(one) > strlen(two)) { + ret = 1; + goto cleanup; + } + if (strlen(two) > strlen(one)) { + ret = -1; + goto cleanup; + } + } - rc = strverscmp(one, two); - if(rc) return(rc); + /* strcmp will return which one is greater - even if the two */ + /* segments are alpha or if they are numeric. don't return */ + /* if they are equal because there might be more segments to */ + /* compare */ + rc = strcmp(one, two); + if (rc) { + ret = rc < 1 ? -1 : 1; + goto cleanup; + } + /* restore character that was replaced by null above */ *ptr1 = oldch1; - *ptr2 = oldch2; one = ptr1; + *ptr2 = oldch2; two = ptr2; } - if((!*one) && (!*two)) { - /* compare release numbers */ - if(rel1 && rel2 && strlen(rel1) && strlen(rel2)) return(_alpm_versioncmp(rel1, rel2)); - return(0); + /* this catches the case where all numeric and alpha segments have */ + /* compared identically but the segment separating characters were */ + /* different */ + if ((!*one) && (!*two)) { + ret = 0; + goto cleanup; + } + + /* libalpm added code. one version string may have a pkgrel number, the + * other may not. unless both have them, we ignore it and return 0. */ + if( (*one && *one == '-') || (*two && *two == '-') ) { + ret = 0; + goto cleanup; + } + + /* whichever version still has characters left over wins */ + if (!*one) { + ret = -1; + } else { + ret = 1; } - return(*one ? 1 : -1); +cleanup: + free(str1); + free(str2); + return(ret); } -pmpkg_t *_alpm_pkg_new(const char *name, const char *version) +pmpkg_t *_alpm_pkg_new(void) { pmpkg_t* pkg; @@ -759,47 +727,56 @@ pmpkg_t *_alpm_pkg_new(const char *name, const char *version) CALLOC(pkg, 1, sizeof(pmpkg_t), RET_ERR(PM_ERR_MEMORY, NULL)); - if(name && name[0] != 0) { - strncpy(pkg->name, name, PKG_NAME_LEN); - } else { - pkg->name[0] = '\0'; - } - if(version && version[0] != 0) { - strncpy(pkg->version, version, PKG_VERSION_LEN); - } else { - pkg->version[0] = '\0'; - } - return(pkg); } pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg) { - pmpkg_t* newpkg; + pmpkg_t *newpkg; + alpm_list_t *i; ALPM_LOG_FUNC; CALLOC(newpkg, 1, sizeof(pmpkg_t), RET_ERR(PM_ERR_MEMORY, NULL)); - memcpy(newpkg, pkg, sizeof(pmpkg_t)); + STRDUP(newpkg->filename, pkg->filename, RET_ERR(PM_ERR_MEMORY, newpkg)); + STRDUP(newpkg->name, pkg->name, RET_ERR(PM_ERR_MEMORY, newpkg)); + STRDUP(newpkg->version, pkg->version, RET_ERR(PM_ERR_MEMORY, newpkg)); + STRDUP(newpkg->desc, pkg->desc, RET_ERR(PM_ERR_MEMORY, newpkg)); + STRDUP(newpkg->url, pkg->url, RET_ERR(PM_ERR_MEMORY, newpkg)); + newpkg->builddate = pkg->builddate; + newpkg->installdate = pkg->installdate; + STRDUP(newpkg->packager, pkg->packager, RET_ERR(PM_ERR_MEMORY, newpkg)); + STRDUP(newpkg->md5sum, pkg->md5sum, RET_ERR(PM_ERR_MEMORY, newpkg)); + STRDUP(newpkg->arch, pkg->arch, RET_ERR(PM_ERR_MEMORY, newpkg)); + newpkg->size = pkg->size; + newpkg->isize = pkg->isize; + newpkg->scriptlet = pkg->scriptlet; + newpkg->force = pkg->force; + newpkg->reason = pkg->reason; + newpkg->licenses = alpm_list_strdup(alpm_pkg_get_licenses(pkg)); - newpkg->conflicts = alpm_list_strdup(alpm_pkg_get_conflicts(pkg)); + newpkg->replaces = alpm_list_strdup(alpm_pkg_get_replaces(pkg)); + newpkg->groups = alpm_list_strdup(alpm_pkg_get_groups(pkg)); newpkg->files = alpm_list_strdup(alpm_pkg_get_files(pkg)); newpkg->backup = alpm_list_strdup(alpm_pkg_get_backup(pkg)); - newpkg->depends = alpm_list_copy_data(alpm_pkg_get_depends(pkg), - sizeof(pmdepend_t)); + for(i = alpm_pkg_get_depends(pkg); i; i = alpm_list_next(i)) { + newpkg->depends = alpm_list_add(newpkg->depends, _alpm_dep_dup(i->data)); + } newpkg->optdepends = alpm_list_strdup(alpm_pkg_get_optdepends(pkg)); - newpkg->groups = alpm_list_strdup(alpm_pkg_get_groups(pkg)); + newpkg->conflicts = alpm_list_strdup(alpm_pkg_get_conflicts(pkg)); newpkg->provides = alpm_list_strdup(alpm_pkg_get_provides(pkg)); - newpkg->replaces = alpm_list_strdup(alpm_pkg_get_replaces(pkg)); newpkg->deltas = alpm_list_copy_data(alpm_pkg_get_deltas(pkg), - sizeof(pmdelta_t)); + sizeof(pmdelta_t)); + /* internal */ + newpkg->origin = pkg->origin; if(newpkg->origin == PKG_FROM_FILE) { newpkg->origin_data.file = strdup(pkg->origin_data.file); } else { newpkg->origin_data.db = pkg->origin_data.db; } + newpkg->infolevel = pkg->infolevel; return(newpkg); } @@ -812,16 +789,28 @@ void _alpm_pkg_free(pmpkg_t *pkg) return; } + FREE(pkg->filename); + FREE(pkg->name); + FREE(pkg->version); + FREE(pkg->desc); + FREE(pkg->url); + FREE(pkg->packager); + FREE(pkg->md5sum); + FREE(pkg->arch); FREELIST(pkg->licenses); + FREELIST(pkg->replaces); + FREELIST(pkg->groups); FREELIST(pkg->files); FREELIST(pkg->backup); - FREELIST(pkg->depends); + alpm_list_free_inner(pkg->depends, (alpm_list_fn_free)_alpm_dep_free); + alpm_list_free(pkg->depends); FREELIST(pkg->optdepends); FREELIST(pkg->conflicts); - FREELIST(pkg->groups); FREELIST(pkg->provides); - FREELIST(pkg->replaces); - FREELIST(pkg->deltas); + alpm_list_free_inner(pkg->deltas, (alpm_list_fn_free)_alpm_delta_free); + alpm_list_free(pkg->deltas); + alpm_list_free(pkg->delta_path); + if(pkg->origin == PKG_FROM_FILE) { FREE(pkg->origin_data.file); } @@ -841,7 +830,7 @@ int _alpm_pkg_compare_versions(pmpkg_t *local_pkg, pmpkg_t *pkg) } /* compare versions and see if we need to upgrade */ - cmp = _alpm_versioncmp(alpm_pkg_get_version(pkg), alpm_pkg_get_version(local_pkg)); + cmp = alpm_pkg_vercmp(alpm_pkg_get_version(pkg), alpm_pkg_get_version(local_pkg)); if(cmp != 0 && pkg->force) { cmp = 1; @@ -863,269 +852,15 @@ int _alpm_pkg_compare_versions(pmpkg_t *local_pkg, pmpkg_t *pkg) */ int _alpm_pkg_cmp(const void *p1, const void *p2) { - pmpkg_t *pk1 = (pmpkg_t *)p1; - pmpkg_t *pk2 = (pmpkg_t *)p2; - - return(strcmp(alpm_pkg_get_name(pk1), alpm_pkg_get_name(pk2))); -} - -/* Parses the package description file for the current package - * TODO: this should ALL be in a backend interface (be_files), we should - * be dealing with the abstracted concepts only in this file - * Returns: 0 on success, 1 on error - * - */ -static int parse_descfile(const char *descfile, pmpkg_t *info) -{ - FILE* fp = NULL; - char line[PATH_MAX]; - char *ptr = NULL; - char *key = NULL; - int linenum = 0; - - ALPM_LOG_FUNC; - - if((fp = fopen(descfile, "r")) == NULL) { - _alpm_log(PM_LOG_ERROR, _("could not open file %s: %s\n"), descfile, strerror(errno)); - return(-1); - } - - while(!feof(fp)) { - fgets(line, PATH_MAX, fp); - linenum++; - _alpm_strtrim(line); - if(strlen(line) == 0 || line[0] == '#') { - continue; - } - ptr = line; - key = strsep(&ptr, "="); - if(key == NULL || ptr == NULL) { - _alpm_log(PM_LOG_DEBUG, "%s: syntax error in description file line %d\n", - info->name[0] != '\0' ? info->name : "error", linenum); - } else { - _alpm_strtrim(key); - _alpm_strtrim(ptr); - if(!strcmp(key, "pkgname")) { - strncpy(info->name, ptr, sizeof(info->name)); - } else if(!strcmp(key, "pkgver")) { - strncpy(info->version, ptr, sizeof(info->version)); - } else if(!strcmp(key, "pkgdesc")) { - strncpy(info->desc, ptr, sizeof(info->desc)); - } else if(!strcmp(key, "group")) { - info->groups = alpm_list_add(info->groups, strdup(ptr)); - } else if(!strcmp(key, "url")) { - strncpy(info->url, ptr, sizeof(info->url)); - } else if(!strcmp(key, "license")) { - info->licenses = alpm_list_add(info->licenses, strdup(ptr)); - } else if(!strcmp(key, "builddate")) { - char first = tolower(ptr[0]); - if(first > 'a' && first < 'z') { - struct tm tmp_tm = {0}; //initialize to null incase of failure - setlocale(LC_TIME, "C"); - strptime(ptr, "%a %b %e %H:%M:%S %Y", &tmp_tm); - info->builddate = mktime(&tmp_tm); - setlocale(LC_TIME, ""); - } else { - info->builddate = atol(ptr); - } - } else if(!strcmp(key, "packager")) { - strncpy(info->packager, ptr, sizeof(info->packager)); - } else if(!strcmp(key, "arch")) { - strncpy(info->arch, ptr, sizeof(info->arch)); - } else if(!strcmp(key, "size")) { - /* size in the raw package is uncompressed (installed) size */ - info->isize = atol(ptr); - } else if(!strcmp(key, "depend")) { - pmdepend_t *dep = alpm_splitdep(ptr); - info->depends = alpm_list_add(info->depends, dep); - } else if(!strcmp(key, "optdepend")) { - info->optdepends = alpm_list_add(info->optdepends, strdup(ptr)); - } else if(!strcmp(key, "conflict")) { - info->conflicts = alpm_list_add(info->conflicts, strdup(ptr)); - } else if(!strcmp(key, "replaces")) { - info->replaces = alpm_list_add(info->replaces, strdup(ptr)); - } else if(!strcmp(key, "provides")) { - info->provides = alpm_list_add(info->provides, strdup(ptr)); - } else if(!strcmp(key, "backup")) { - info->backup = alpm_list_add(info->backup, strdup(ptr)); - } else { - _alpm_log(PM_LOG_DEBUG, "%s: syntax error in description file line %d\n", - info->name[0] != '\0' ? info->name : "error", linenum); - } - } - line[0] = '\0'; - } - fclose(fp); - unlink(descfile); - - return(0); -} - - -/** - * Load a package and create the corresponding pmpkg_t struct. - * @param pkgfile path to the package file - * @param full whether to stop the load after metadata is read or continue - * through the full archive - * @return An information filled pmpkg_t struct - */ -pmpkg_t *_alpm_pkg_load(const char *pkgfile, unsigned short full) -{ - int ret = ARCHIVE_OK; - int config = 0; - struct archive *archive; - struct archive_entry *entry; - pmpkg_t *info = NULL; - char *descfile = NULL; - int fd = -1; - struct stat st; - - ALPM_LOG_FUNC; - - if(pkgfile == NULL || strlen(pkgfile) == 0) { - RET_ERR(PM_ERR_WRONG_ARGS, NULL); - } - - if((archive = archive_read_new()) == NULL) { - RET_ERR(PM_ERR_LIBARCHIVE_ERROR, NULL); - } - - archive_read_support_compression_all(archive); - archive_read_support_format_all(archive); - - if (archive_read_open_filename(archive, pkgfile, - ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { - RET_ERR(PM_ERR_PKG_OPEN, NULL); - } - - info = _alpm_pkg_new(NULL, NULL); - if(info == NULL) { - archive_read_finish(archive); - RET_ERR(PM_ERR_MEMORY, NULL); - } - - if(stat(pkgfile, &st) == 0) { - info->size = st.st_size; - } - - /* TODO there is no reason to make temp files to read - * from a libarchive archive, it can be done by reading - * directly from the archive - * See: archive_read_data_into_buffer - * requires changes 'parse_descfile' as well - * */ - - /* If full is false, only read through the archive until we find our needed - * metadata. If it is true, read through the entire archive, which serves - * as a verfication of integrity and allows us to create the filelist. */ - while((ret = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) { - const char *entry_name = archive_entry_pathname(entry); - - /* NOTE: we used to look for .FILELIST, but it is easier (and safer) for - * us to just generate this on our own. */ - if(strcmp(entry_name, ".PKGINFO") == 0) { - /* extract this file into /tmp. it has info for us */ - descfile = strdup("/tmp/alpm_XXXXXX"); - fd = mkstemp(descfile); - if(archive_read_data_into_fd(archive, fd) != ARCHIVE_OK) { - _alpm_log(PM_LOG_ERROR, _("error extracting package description file to %s\n"), - descfile); - goto pkg_invalid; - } - /* parse the info file */ - if(parse_descfile(descfile, info) == -1) { - _alpm_log(PM_LOG_ERROR, _("could not parse package description file in %s\n"), - pkgfile); - goto pkg_invalid; - } - if(!strlen(info->name)) { - _alpm_log(PM_LOG_ERROR, _("missing package name in %s\n"), pkgfile); - goto pkg_invalid; - } - if(!strlen(info->version)) { - _alpm_log(PM_LOG_ERROR, _("missing package version in %s\n"), pkgfile); - goto pkg_invalid; - } - config = 1; - unlink(descfile); - FREE(descfile); - close(fd); - continue; - } else if(strcmp(entry_name, ".INSTALL") == 0) { - info->scriptlet = 1; - } else if(*entry_name == '.') { - /* for now, ignore all files starting with '.' that haven't - * already been handled (for future possibilities) */ - } else { - /* Keep track of all files for filelist generation */ - info->files = alpm_list_add(info->files, strdup(entry_name)); - } - - if(archive_read_data_skip(archive)) { - _alpm_log(PM_LOG_ERROR, _("error while reading package %s: %s\n"), - pkgfile, archive_error_string(archive)); - pm_errno = PM_ERR_LIBARCHIVE_ERROR; - goto error; - } - - /* if we are not doing a full read, see if we have all we need */ - if(!full && config) { - break; - } - } - - if(ret != ARCHIVE_EOF && ret != ARCHIVE_OK) { /* An error occured */ - _alpm_log(PM_LOG_ERROR, _("error while reading package %s: %s\n"), - pkgfile, archive_error_string(archive)); - pm_errno = PM_ERR_LIBARCHIVE_ERROR; - goto error; - } - - if(!config) { - _alpm_log(PM_LOG_ERROR, _("missing package metadata in %s\n"), pkgfile); - goto pkg_invalid; - } - - archive_read_finish(archive); - - /* internal fields for package struct */ - info->origin = PKG_FROM_FILE; - info->origin_data.file = strdup(pkgfile); - - if(full) { - /* "checking for conflicts" requires a sorted list, so we ensure that here */ - _alpm_log(PM_LOG_DEBUG, "sorting package filelist for %s\n", pkgfile); - info->files = alpm_list_msort(info->files, alpm_list_count(info->files), - _alpm_str_cmp); - info->infolevel = INFRQ_ALL; - } else { - /* get rid of any partial filelist we may have collected, as it is invalid */ - FREELIST(info->files); - info->infolevel = INFRQ_BASE | INFRQ_DESC | INFRQ_DEPENDS; - } - - return(info); - -pkg_invalid: - pm_errno = PM_ERR_PKG_INVALID; - if(descfile) { - unlink(descfile); - FREE(descfile); - } - if(fd != -1) { - close(fd); - } -error: - _alpm_pkg_free(info); - archive_read_finish(archive); - - return(NULL); + pmpkg_t *pkg1 = (pmpkg_t *)p1; + pmpkg_t *pkg2 = (pmpkg_t *)p2; + return(strcmp(alpm_pkg_get_name(pkg1), alpm_pkg_get_name(pkg2))); } /* Test for existence of a package in a alpm_list_t* * of pmpkg_t* */ -pmpkg_t *_alpm_pkg_find(const char *needle, alpm_list_t *haystack) +pmpkg_t *_alpm_pkg_find(alpm_list_t *haystack, const char *needle) { alpm_list_t *lp; diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h index d6c3eff9..ddf1d073 100644 --- a/lib/libalpm/package.h +++ b/lib/libalpm/package.h @@ -33,30 +33,17 @@ typedef enum _pmpkgfrom_t { PKG_FROM_FILE } pmpkgfrom_t; -/* Packages */ -#define PKG_FILENAME_LEN 512 -#define PKG_NAME_LEN 256 -#define PKG_VERSION_LEN 64 -#define PKG_FULLNAME_LEN (PKG_NAME_LEN + PKG_VERSION_LEN) -#define PKG_DESC_LEN 512 -#define PKG_URL_LEN 256 -#define PKG_DATE_LEN 32 -#define PKG_TYPE_LEN 32 -#define PKG_PACKAGER_LEN 64 -#define PKG_MD5SUM_LEN 33 -#define PKG_ARCH_LEN 32 - struct __pmpkg_t { - char filename[PKG_FILENAME_LEN]; - char name[PKG_NAME_LEN]; - char version[PKG_VERSION_LEN]; - char desc[PKG_DESC_LEN]; - char url[PKG_URL_LEN]; + char *filename; + char *name; + char *version; + char *desc; + char *url; time_t builddate; time_t installdate; - char packager[PKG_PACKAGER_LEN]; - char md5sum[PKG_MD5SUM_LEN]; - char arch[PKG_ARCH_LEN]; + char *packager; + char *md5sum; + char *arch; unsigned long size; unsigned long isize; unsigned short scriptlet; @@ -83,16 +70,16 @@ struct __pmpkg_t { char *file; } origin_data; pmdbinfrq_t infolevel; + unsigned long download_size; + alpm_list_t *delta_path; }; -int _alpm_versioncmp(const char *a, const char *b); -pmpkg_t* _alpm_pkg_new(const char *name, const char *version); +pmpkg_t* _alpm_pkg_new(void); pmpkg_t *_alpm_pkg_dup(pmpkg_t *pkg); void _alpm_pkg_free(pmpkg_t *pkg); int _alpm_pkg_cmp(const void *p1, const void *p2); int _alpm_pkg_compare_versions(pmpkg_t *local_pkg, pmpkg_t *pkg); -pmpkg_t *_alpm_pkg_load(const char *pkgfile, unsigned short full); -pmpkg_t *_alpm_pkg_find(const char *needle, alpm_list_t *haystack); +pmpkg_t *_alpm_pkg_find(alpm_list_t *haystack, const char *needle); int _alpm_pkg_should_ignore(pmpkg_t *pkg); #endif /* _ALPM_PACKAGE_H */ diff --git a/lib/libalpm/po/POTFILES.in b/lib/libalpm/po/POTFILES.in index 80130f24..35bd864b 100644 --- a/lib/libalpm/po/POTFILES.in +++ b/lib/libalpm/po/POTFILES.in @@ -10,6 +10,7 @@ lib/libalpm/conflict.c lib/libalpm/db.c lib/libalpm/delta.c lib/libalpm/deps.c +lib/libalpm/dload.c lib/libalpm/error.c lib/libalpm/group.c lib/libalpm/handle.c @@ -17,7 +18,6 @@ lib/libalpm/log.c lib/libalpm/md5.c lib/libalpm/package.c lib/libalpm/remove.c -lib/libalpm/server.c lib/libalpm/sync.c lib/libalpm/trans.c lib/libalpm/util.c diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index a0f9963a..625abe67 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -37,7 +37,6 @@ #include "alpm_list.h" #include "trans.h" #include "util.h" -#include "error.h" #include "log.h" #include "backup.h" #include "package.h" @@ -57,7 +56,7 @@ int _alpm_remove_loadtarget(pmtrans_t *trans, pmdb_t *db, char *name) ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1)); ASSERT(name != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1)); - if(_alpm_pkg_find(name, trans->packages)) { + if(_alpm_pkg_find(trans->packages, name)) { RET_ERR(PM_ERR_TRANS_DUP_TARGET, -1); } @@ -82,6 +81,60 @@ int _alpm_remove_loadtarget(pmtrans_t *trans, pmdb_t *db, char *name) return(0); } +static void remove_prepare_cascade(pmtrans_t *trans, pmdb_t *db, + alpm_list_t *lp) +{ + ALPM_LOG_FUNC; + + while(lp) { + alpm_list_t *i; + for(i = lp; i; i = i->next) { + pmdepmissing_t *miss = (pmdepmissing_t *)i->data; + pmpkg_t *info = _alpm_db_get_pkgfromcache(db, miss->target); + if(info) { + if(!_alpm_pkg_find(trans->packages, alpm_pkg_get_name(info))) { + _alpm_log(PM_LOG_DEBUG, "pulling %s in the targets list\n", + alpm_pkg_get_name(info)); + trans->packages = alpm_list_add(trans->packages, _alpm_pkg_dup(info)); + } + } else { + _alpm_log(PM_LOG_ERROR, _("could not find %s in database -- skipping\n"), + miss->target); + } + } + alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free); + alpm_list_free(lp); + lp = alpm_checkdeps(db, 1, trans->packages, NULL); + } +} + +static void remove_prepare_keep_needed(pmtrans_t *trans, pmdb_t *db, + alpm_list_t *lp) +{ + ALPM_LOG_FUNC; + + /* Remove needed packages (which break dependencies) from the target list */ + while(lp != NULL) { + alpm_list_t *i; + for(i = lp; i; i = i->next) { + pmdepmissing_t *miss = (pmdepmissing_t *)i->data; + void *vpkg; + pmpkg_t *pkg = _alpm_pkg_find(trans->packages, miss->causingpkg); + trans->packages = alpm_list_remove(trans->packages, pkg, _alpm_pkg_cmp, + &vpkg); + pkg = vpkg; + if(pkg) { + _alpm_log(PM_LOG_WARNING, "removing %s from the target-list\n", + alpm_pkg_get_name(pkg)); + _alpm_pkg_free(pkg); + } + } + alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free); + alpm_list_free(lp); + lp = alpm_checkdeps(db, 1, trans->packages, NULL); + } +} + int _alpm_remove_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data) { alpm_list_t *lp; @@ -96,37 +149,30 @@ int _alpm_remove_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data) return(0); } + if((trans->flags & PM_TRANS_FLAG_RECURSE) && !(trans->flags & PM_TRANS_FLAG_CASCADE)) { + _alpm_log(PM_LOG_DEBUG, "finding removable dependencies\n"); + _alpm_recursedeps(db, trans->packages, trans->flags & PM_TRANS_FLAG_RECURSEALL); + } + if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) { EVENT(trans, PM_TRANS_EVT_CHECKDEPS_START, NULL, NULL); _alpm_log(PM_LOG_DEBUG, "looking for unsatisfied dependencies\n"); lp = alpm_checkdeps(db, 1, trans->packages, NULL); if(lp != NULL) { + if(trans->flags & PM_TRANS_FLAG_CASCADE) { - while(lp) { - alpm_list_t *i; - for(i = lp; i; i = i->next) { - pmdepmissing_t *miss = (pmdepmissing_t *)i->data; - pmpkg_t *info = _alpm_db_get_pkgfromcache(db, miss->target); - if(info) { - if(!_alpm_pkg_find(alpm_pkg_get_name(info), trans->packages)) { - _alpm_log(PM_LOG_DEBUG, "pulling %s in the targets list\n", - alpm_pkg_get_name(info)); - trans->packages = alpm_list_add(trans->packages, _alpm_pkg_dup(info)); - } - } else { - _alpm_log(PM_LOG_ERROR, _("could not find %s in database -- skipping\n"), - miss->target); - } - } - FREELIST(lp); - lp = alpm_checkdeps(db, 1, trans->packages, NULL); - } + remove_prepare_cascade(trans, db, lp); + } else if (trans->flags & PM_TRANS_FLAG_UNNEEDED) { + /* Remove needed packages (which would break dependencies) + * from the target list */ + remove_prepare_keep_needed(trans, db, lp); } else { if(data) { *data = lp; } else { - FREELIST(lp); + alpm_list_free_inner(lp, (alpm_list_fn_free)_alpm_depmiss_free); + alpm_list_free(lp); } RET_ERR(PM_ERR_UNSATISFIED_DEPS, -1); } @@ -135,14 +181,15 @@ int _alpm_remove_prepare(pmtrans_t *trans, pmdb_t *db, alpm_list_t **data) /* re-order w.r.t. dependencies */ _alpm_log(PM_LOG_DEBUG, "sorting by dependencies\n"); - lp = _alpm_sortbydeps(trans->packages, PM_TRANS_TYPE_REMOVE); + lp = _alpm_sortbydeps(trans->packages, 1); /* free the old alltargs */ alpm_list_free(trans->packages); trans->packages = lp; - if(trans->flags & PM_TRANS_FLAG_RECURSE) { + /* -Rcs == -Rc then -Rs */ + if((trans->flags & PM_TRANS_FLAG_CASCADE) && (trans->flags & PM_TRANS_FLAG_RECURSE)) { _alpm_log(PM_LOG_DEBUG, "finding removable dependencies\n"); - _alpm_recursedeps(db, trans->packages, 0); + _alpm_recursedeps(db, trans->packages, trans->flags & PM_TRANS_FLAG_RECURSEALL); } if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) { diff --git a/lib/libalpm/server.c b/lib/libalpm/server.c deleted file mode 100644 index 4bccf3ca..00000000 --- a/lib/libalpm/server.c +++ /dev/null @@ -1,469 +0,0 @@ -/* - * server.c - * - * Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#include <stdlib.h> -#include <errno.h> -#include <time.h> -#include <string.h> -#include <limits.h> -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <download.h> - -/* libalpm */ -#include "server.h" -#include "alpm_list.h" -#include "error.h" -#include "log.h" -#include "alpm.h" -#include "util.h" -#include "handle.h" -#include "package.h" - -pmserver_t *_alpm_server_new(const char *url) -{ - struct url *u; - pmserver_t *server; - - ALPM_LOG_FUNC; - - CALLOC(server, 1, sizeof(pmserver_t), RET_ERR(PM_ERR_MEMORY, NULL)); - - u = downloadParseURL(url); - if(!u) { - _alpm_log(PM_LOG_ERROR, _("url '%s' is invalid, ignoring\n"), url); - RET_ERR(PM_ERR_SERVER_BAD_URL, NULL); - } - if(strlen(u->scheme) == 0) { - _alpm_log(PM_LOG_WARNING, _("url scheme not specified, assuming http\n")); - strcpy(u->scheme, "http"); - } - - if(strcmp(u->scheme,"ftp") == 0 && strlen(u->user) == 0) { - strcpy(u->user, "anonymous"); - strcpy(u->pwd, "libalpm@guest"); - } - - /* remove trailing slashes, just to clean up the rest of the code */ - for(int i = strlen(u->doc) - 1; u->doc[i] == '/'; --i) - u->doc[i] = '\0'; - - server->s_url = u; - - return server; -} - -void _alpm_server_free(pmserver_t *server) -{ - ALPM_LOG_FUNC; - - if(server == NULL) { - return; - } - - /* free memory */ - downloadFreeURL(server->s_url); - FREE(server); -} - -/* remove filename info from "s_url->doc" and return it */ -static char *strip_filename(pmserver_t *server) -{ - char *p = NULL, *fname = NULL; - if(!server) { - return(NULL); - } - - p = strrchr(server->s_url->doc, '/'); - if(p && *(++p)) { - fname = strdup(p); - _alpm_log(PM_LOG_DEBUG, "stripping '%s' from '%s'\n", - fname, server->s_url->doc); - *p = 0; - } - - /* s_url->doc now contains ONLY path information. return value - * if the file information from the original URL */ - return(fname); -} - -/* Return a 'struct url' for this server, for downloading 'filename'. */ -static struct url *url_for_file(pmserver_t *server, const char *filename) -{ - struct url *ret = NULL; - char *doc = NULL; - int doclen = 0; - - doclen = strlen(server->s_url->doc) + strlen(filename) + 2; - CALLOC(doc, doclen, sizeof(char), RET_ERR(PM_ERR_MEMORY, NULL)); - - snprintf(doc, doclen, "%s/%s", server->s_url->doc, filename); - ret = downloadMakeURL(server->s_url->scheme, - server->s_url->host, - server->s_url->port, - doc, - server->s_url->user, - server->s_url->pwd); - FREE(doc); - return(ret); -} - -/* - * Download a list of files from a list of servers - * - if one server fails, we try the next one in the list - * - if *dl_total is non-NULL, then it will be used as the starting - * download amount when TotalDownload is set. It will also be - * set to the final download amount for the calling function to use. - * - totalsize is the total download size for use when TotalDownload - * is set. Use 0 if the total download size is not known. - * - * RETURN: 0 for successful download, 1 on error - */ -int _alpm_downloadfiles(alpm_list_t *servers, const char *localpath, - alpm_list_t *files, int *dl_total, unsigned long totalsize) -{ - return(_alpm_downloadfiles_forreal(servers, localpath, files, 0, NULL, - dl_total, totalsize)); -} - -/* - * This is the real downloadfiles, used directly by sync_synctree() to check - * modtimes on remote files. - * - if mtime1 is non-NULL, then only download files if they are different - * than mtime1. - * - if *mtime2 is non-NULL, it will be filled with the mtime of the remote - * file. - * - if *dl_total is non-NULL, then it will be used as the starting - * download amount when TotalDownload is set. It will also be - * set to the final download amount for the calling function to use. - * - totalsize is the total download size for use when TotalDownload - * is set. Use 0 if the total download size is not known. - * - * RETURN: 0 for successful download - * 1 if the mtimes are identical - * -1 on error - */ -int _alpm_downloadfiles_forreal(alpm_list_t *servers, const char *localpath, - alpm_list_t *files, time_t mtime1, time_t *mtime2, int *dl_total, - unsigned long totalsize) -{ - int dl_thisfile = 0; - alpm_list_t *lp; - int done = 0; - alpm_list_t *complete = NULL; - alpm_list_t *i; - - ALPM_LOG_FUNC; - - if(files == NULL) { - return(0); - } - - for(i = servers; i && !done; i = i->next) { - pmserver_t *server = i->data; - - /* get each file in the list */ - for(lp = files; lp; lp = lp->next) { - struct url *fileurl = NULL; - char realfile[PATH_MAX]; - char output[PATH_MAX]; - char *fn = (char *)lp->data; - char pkgname[PKG_NAME_LEN]; - - fileurl = url_for_file(server, fn); - if(!fileurl) { - return(-1); - } - - /* pass the raw filename for passing to the callback function */ - strncpy(pkgname, fn, PKG_NAME_LEN); - _alpm_log(PM_LOG_DEBUG, "using '%s' for download progress\n", pkgname); - - snprintf(realfile, PATH_MAX, "%s%s", localpath, fn); - snprintf(output, PATH_MAX, "%s%s.part", localpath, fn); - - if(alpm_list_find_str(complete, fn)) { - continue; - } - - if(!handle->xfercommand || !strcmp(fileurl->scheme, "file")) { - FILE *dlf, *localf = NULL; - struct url_stat ust; - struct stat st; - int chk_resume = 0; - - if(stat(output, &st) == 0 && st.st_size > 0) { - _alpm_log(PM_LOG_DEBUG, "existing file found, using it\n"); - fileurl->offset = (off_t)st.st_size; - dl_thisfile = st.st_size; - if (dl_total != NULL) { - *dl_total += st.st_size; - } - localf = fopen(output, "a"); - chk_resume = 1; - } else { - fileurl->offset = (off_t)0; - dl_thisfile = 0; - } - - /* libdownload does not reset the error code, reset it in - * the case of previous errors */ - downloadLastErrCode = 0; - - /* 10s timeout - TODO make a config option */ - downloadTimeout = 10000; - - dlf = downloadXGet(fileurl, &ust, (handle->nopassiveftp ? "" : "p")); - - if(downloadLastErrCode != 0 || dlf == NULL) { - const char *host = _("disk"); - if(strcmp(SCHEME_FILE, fileurl->scheme) != 0) { - host = fileurl->host; - } - _alpm_log(PM_LOG_ERROR, _("failed retrieving file '%s' from %s : %s\n"), - fn, host, downloadLastErrString); - if(localf != NULL) { - fclose(localf); - } - /* try the next server */ - downloadFreeURL(fileurl); - continue; - } else { - _alpm_log(PM_LOG_DEBUG, "connected to %s successfully\n", fileurl->host); - } - - if(ust.mtime && mtime1 && ust.mtime == mtime1) { - _alpm_log(PM_LOG_DEBUG, "mtimes are identical, skipping %s\n", fn); - complete = alpm_list_add(complete, fn); - if(localf != NULL) { - fclose(localf); - } - if(dlf != NULL) { - fclose(dlf); - } - downloadFreeURL(fileurl); - return(1); - } - - if(ust.mtime && mtime2) { - *mtime2 = ust.mtime; - } - - if(chk_resume && fileurl->offset == 0) { - _alpm_log(PM_LOG_WARNING, _("cannot resume download, starting over\n")); - if(localf != NULL) { - fclose(localf); - localf = NULL; - } - } - - if(localf == NULL) { - _alpm_rmrf(output); - fileurl->offset = (off_t)0; - dl_thisfile = 0; - localf = fopen(output, "w"); - if(localf == NULL) { /* still null? */ - _alpm_log(PM_LOG_ERROR, _("cannot write to file '%s'\n"), output); - if(dlf != NULL) { - fclose(dlf); - } - downloadFreeURL(fileurl); - return(-1); - } - } - - /* Progress 0 - initialize */ - if(handle->dlcb) { - handle->dlcb(pkgname, 0, ust.size, dl_total ? *dl_total : 0, - totalsize); - } - - int nread = 0; - char buffer[PM_DLBUF_LEN]; - while((nread = fread(buffer, 1, PM_DLBUF_LEN, dlf)) > 0) { - if(ferror(dlf)) { - _alpm_log(PM_LOG_ERROR, _("error downloading '%s': %s\n"), - fn, downloadLastErrString); - fclose(localf); - fclose(dlf); - downloadFreeURL(fileurl); - return(-1); - } - - int nwritten = 0; - while(nwritten < nread) { - nwritten += fwrite(buffer, 1, (nread - nwritten), localf); - if(ferror(localf)) { - _alpm_log(PM_LOG_ERROR, _("error writing to file '%s': %s\n"), - realfile, strerror(errno)); - fclose(localf); - fclose(dlf); - downloadFreeURL(fileurl); - return(-1); - } - } - - if(nwritten != nread) { - - } - dl_thisfile += nread; - if (dl_total != NULL) { - *dl_total += nread; - } - - if(handle->dlcb) { - handle->dlcb(pkgname, dl_thisfile, ust.size, - dl_total ? *dl_total : 0, totalsize); - } - } - - downloadFreeURL(fileurl); - fclose(localf); - fclose(dlf); - rename(output, realfile); - complete = alpm_list_add(complete, fn); - } else { - int ret; - int usepart = 0; - char *ptr1, *ptr2; - char origCmd[PATH_MAX]; - char parsedCmd[PATH_MAX] = ""; - char url[PATH_MAX]; - char cwd[PATH_MAX]; - - /* build the full download url */ - snprintf(url, PATH_MAX, "%s://%s%s", fileurl->scheme, - fileurl->host, fileurl->doc); - /* we don't need this anymore */ - downloadFreeURL(fileurl); - - /* replace all occurrences of %o with fn.part */ - strncpy(origCmd, handle->xfercommand, sizeof(origCmd)); - ptr1 = origCmd; - while((ptr2 = strstr(ptr1, "%o"))) { - usepart = 1; - ptr2[0] = '\0'; - strcat(parsedCmd, ptr1); - strcat(parsedCmd, output); - ptr1 = ptr2 + 2; - } - strcat(parsedCmd, ptr1); - /* replace all occurrences of %u with the download URL */ - strncpy(origCmd, parsedCmd, sizeof(origCmd)); - parsedCmd[0] = '\0'; - ptr1 = origCmd; - while((ptr2 = strstr(ptr1, "%u"))) { - ptr2[0] = '\0'; - strcat(parsedCmd, ptr1); - strcat(parsedCmd, url); - ptr1 = ptr2 + 2; - } - strcat(parsedCmd, ptr1); - /* cwd to the download directory */ - getcwd(cwd, PATH_MAX); - if(chdir(localpath)) { - _alpm_log(PM_LOG_WARNING, _("could not chdir to %s\n"), localpath); - return(PM_ERR_CONNECT_FAILED); - } - /* execute the parsed command via /bin/sh -c */ - _alpm_log(PM_LOG_DEBUG, "running command: %s\n", parsedCmd); - ret = system(parsedCmd); - if(ret == -1) { - _alpm_log(PM_LOG_WARNING, _("running XferCommand: fork failed!\n")); - return(PM_ERR_FORK_FAILED); - } else if(ret != 0) { - /* download failed */ - _alpm_log(PM_LOG_DEBUG, "XferCommand command returned non-zero status code (%d)\n", ret); - } else { - /* download was successful */ - complete = alpm_list_add(complete, fn); - if(usepart) { - rename(output, realfile); - } - } - chdir(cwd); - } - } - - if(alpm_list_count(complete) == alpm_list_count(files)) { - done = 1; - } - } - alpm_list_free(complete); - - return(done ? 0 : -1); -} - -/** Fetch a remote pkg. - * @param url URL of the package to download - * @return the downloaded filepath on success, NULL on error - * @addtogroup alpm_misc - */ -char SYMEXPORT *alpm_fetch_pkgurl(const char *url) -{ - pmserver_t *server; - char *filename, *filepath; - const char *cachedir; - - ALPM_LOG_FUNC; - - if(strstr(url, "://") == NULL) { - _alpm_log(PM_LOG_DEBUG, "Invalid URL passed to alpm_fetch_pkgurl\n"); - return(NULL); - } - - server = _alpm_server_new(url); - if(!server) { - return(NULL); - } - - /* strip path information from the filename */ - filename = strip_filename(server); - if(!filename) { - _alpm_log(PM_LOG_ERROR, _("URL does not contain a file for download\n")); - return(NULL); - } - - /* find a valid cache dir to download to */ - cachedir = _alpm_filecache_setup(); - - /* TODO this seems like needless complexity just to download one file */ - alpm_list_t *servers = alpm_list_add(NULL, server); - alpm_list_t *files = alpm_list_add(NULL, filename); - - /* download the file */ - if(_alpm_downloadfiles(servers, cachedir, files, NULL, 0)) { - _alpm_log(PM_LOG_WARNING, _("failed to download %s\n"), url); - return(NULL); - } - _alpm_log(PM_LOG_DEBUG, "successfully downloaded %s\n", filename); - alpm_list_free(files); - alpm_list_free(servers); - _alpm_server_free(server); - - /* we should be able to find the file the second time around */ - filepath = _alpm_filecache_find(filename); - return(filepath); -} - -/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/server.h b/lib/libalpm/server.h deleted file mode 100644 index b82fcb09..00000000 --- a/lib/libalpm/server.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * server.h - * - * Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef _ALPM_SERVER_H -#define _ALPM_SERVER_H - -#include "alpm_list.h" -#include "alpm.h" - -#include <time.h> -#include <download.h> - -/* Servers */ -struct __pmserver_t { - /* useless abstraction now? */ - struct url *s_url; -}; - -#define PM_DLBUF_LEN (1024 * 10) - -pmserver_t *_alpm_server_new(const char *url); -void _alpm_server_free(pmserver_t *server); -int _alpm_downloadfiles(alpm_list_t *servers, const char *localpath, - alpm_list_t *files, int *dl_total, unsigned long totalsize); -int _alpm_downloadfiles_forreal(alpm_list_t *servers, const char *localpath, - alpm_list_t *files, time_t mtime1, time_t *mtime2, int *dl_total, - unsigned long totalsize); - -#endif /* _ALPM_SERVER_H */ - -/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index a927f61b..0d6a6ee3 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -34,7 +34,6 @@ #include "sync.h" #include "alpm_list.h" #include "log.h" -#include "error.h" #include "package.h" #include "db.h" #include "cache.h" @@ -44,10 +43,10 @@ #include "util.h" #include "handle.h" #include "alpm.h" -#include "server.h" +#include "dload.h" #include "delta.h" -pmsyncpkg_t *_alpm_sync_new(int type, pmpkg_t *spkg, void *data) +pmsyncpkg_t *_alpm_sync_new(pmpkgreason_t newreason, pmpkg_t *spkg, alpm_list_t *removes) { pmsyncpkg_t *sync; @@ -55,9 +54,9 @@ pmsyncpkg_t *_alpm_sync_new(int type, pmpkg_t *spkg, void *data) CALLOC(sync, 1, sizeof(pmsyncpkg_t), RET_ERR(PM_ERR_MEMORY, NULL)); - sync->type = type; + sync->newreason = newreason; sync->pkg = spkg; - sync->data = data; + sync->removes = removes; return(sync); } @@ -70,32 +69,11 @@ void _alpm_sync_free(pmsyncpkg_t *sync) return; } - /* TODO wow this is ugly */ - if(sync->type == PM_SYNC_TYPE_REPLACE) { - alpm_list_free_inner(sync->data, (alpm_list_fn_free)_alpm_pkg_free); - alpm_list_free(sync->data); - sync->data = NULL; - } else { - _alpm_pkg_free(sync->data); - sync->data = NULL; - } + alpm_list_free(sync->removes); + sync->removes = NULL; FREE(sync); } -static void synclist_free(alpm_list_t *syncpkgs) -{ - if(syncpkgs) { - alpm_list_t *tmp; - for(tmp = syncpkgs; tmp; tmp = alpm_list_next(tmp)) { - if(tmp->data) { - _alpm_sync_free(tmp->data); - } - } - alpm_list_free(syncpkgs); - } - -} - /* Find recommended replacements for packages during a sync. */ static int find_replacements(pmtrans_t *trans, pmdb_t *db_local, @@ -147,27 +125,29 @@ static int find_replacements(pmtrans_t *trans, pmdb_t *db_local, * the package to replace. */ pmsyncpkg_t *sync; - pmpkg_t *dummy = _alpm_pkg_dup(lpkg); - if(dummy == NULL) { - pm_errno = PM_ERR_MEMORY; - synclist_free(*syncpkgs); - return(-1); - } + /* check if spkg->name is already in the packages list. */ + /* TODO: same package name doesn't mean same package */ sync = _alpm_sync_find(*syncpkgs, alpm_pkg_get_name(spkg)); if(sync) { - /* found it -- just append to the replaces list */ - sync->data = alpm_list_add(sync->data, dummy); + /* found it -- just append to the removes list */ + sync->removes = alpm_list_add(sync->removes, lpkg); + /* check the to-be-replaced package's reason field */ + if(lpkg->reason == PM_PKG_REASON_EXPLICIT) { + sync->newreason = PM_PKG_REASON_EXPLICIT; + } } else { /* none found -- enter pkg into the final sync list */ - sync = _alpm_sync_new(PM_SYNC_TYPE_REPLACE, spkg, NULL); + /* copy over reason */ + sync = _alpm_sync_new(alpm_pkg_get_reason(lpkg), spkg, NULL); if(sync == NULL) { - _alpm_pkg_free(dummy); pm_errno = PM_ERR_MEMORY; - synclist_free(*syncpkgs); + alpm_list_free_inner(*syncpkgs, (alpm_list_fn_free)_alpm_sync_free); + alpm_list_free(*syncpkgs); + *syncpkgs = NULL; return(-1); } - sync->data = alpm_list_add(NULL, dummy); + sync->removes = alpm_list_add(NULL, lpkg); *syncpkgs = alpm_list_add(*syncpkgs, sync); } _alpm_log(PM_LOG_DEBUG, "%s-%s elected for removal (to be replaced by %s-%s)\n", @@ -180,6 +160,35 @@ static int find_replacements(pmtrans_t *trans, pmdb_t *db_local, return(0); } +/** Check for new version of pkg in sync repos + * (only the first occurrence is considered in sync) + */ +pmpkg_t SYMEXPORT *alpm_sync_newversion(pmpkg_t *pkg, alpm_list_t *dbs_sync) +{ + alpm_list_t *i; + pmpkg_t *spkg = NULL; + + for(i = dbs_sync; !spkg && i; i = i->next) { + spkg = _alpm_db_get_pkgfromcache(i->data, alpm_pkg_get_name(pkg)); + } + + if(spkg == NULL) { + _alpm_log(PM_LOG_DEBUG, "'%s' not found in sync db => no upgrade\n", + alpm_pkg_get_name(pkg)); + return(NULL); + } + + /* compare versions and see if spkg is an upgrade */ + if(_alpm_pkg_compare_versions(pkg, spkg)) { + _alpm_log(PM_LOG_DEBUG, "new version of '%s' found (%s => %s)\n", + alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg), + alpm_pkg_get_version(spkg)); + return(spkg); + } else { + return(NULL); + } +} + /** Get a list of upgradable packages on the current system * Adds out of date packages to *list. * @arg list pointer to a list of pmsyncpkg_t. @@ -193,7 +202,7 @@ int SYMEXPORT alpm_sync_sysupgrade(pmdb_t *db_local, int _alpm_sync_sysupgrade(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync, alpm_list_t **syncpkgs) { - alpm_list_t *i, *j; + alpm_list_t *i, *j, *replaced = NULL; ALPM_LOG_FUNC; @@ -205,76 +214,61 @@ int _alpm_sync_sysupgrade(pmtrans_t *trans, return(-1); } - /* match installed packages with the sync dbs and compare versions */ + /* compute the to-be-replaced packages for efficiency */ + for(i = *syncpkgs; i; i = i->next) { + pmsyncpkg_t *sync = i->data; + for(j = sync->removes; j; j = j->next) { + replaced = alpm_list_add(replaced, j->data); + } + } + + /* for all not-replaced local package we check for upgrade */ _alpm_log(PM_LOG_DEBUG, "checking for package upgrades\n"); for(i = _alpm_db_get_pkgcache(db_local); i; i = i->next) { - int replace = 0; pmpkg_t *local = i->data; - pmpkg_t *spkg = NULL; - pmsyncpkg_t *sync; - for(j = dbs_sync; !spkg && j; j = j->next) { - spkg = _alpm_db_get_pkgfromcache(j->data, alpm_pkg_get_name(local)); - } - if(spkg == NULL) { - _alpm_log(PM_LOG_DEBUG, "'%s' not found in sync db -- skipping\n", - alpm_pkg_get_name(local)); - continue; - } - - /* we don't care about a to-be-replaced package's newer version */ - for(j = *syncpkgs; j && !replace; j=j->next) { - sync = j->data; - if(sync->type == PM_SYNC_TYPE_REPLACE) { - if(_alpm_pkg_find(alpm_pkg_get_name(spkg), sync->data)) { - replace = 1; - } - } - } - if(replace) { + if(_alpm_pkg_find(replaced, alpm_pkg_get_name(local))) { _alpm_log(PM_LOG_DEBUG, "'%s' is already elected for removal -- skipping\n", alpm_pkg_get_name(local)); continue; } - /* compare versions and see if we need to upgrade */ - if(_alpm_pkg_compare_versions(local, spkg)) { - _alpm_log(PM_LOG_DEBUG, "%s elected for upgrade (%s => %s)\n", - alpm_pkg_get_name(local), alpm_pkg_get_version(local), - alpm_pkg_get_version(spkg)); - if(!_alpm_sync_find(*syncpkgs, alpm_pkg_get_name(spkg))) { - /* If package is in the ignorepkg list, skip it */ - if(_alpm_pkg_should_ignore(spkg)) { - _alpm_log(PM_LOG_WARNING, _("%s: ignoring package upgrade (%s => %s)\n"), - alpm_pkg_get_name(local), alpm_pkg_get_version(local), - alpm_pkg_get_version(spkg)); - continue; - } + pmpkg_t *spkg = alpm_sync_newversion(local, dbs_sync); + if(spkg) { + /* we found a new version */ + /* skip packages in IgnorePkg or in IgnoreGroup */ + if(_alpm_pkg_should_ignore(spkg)) { + _alpm_log(PM_LOG_WARNING, _("%s: ignoring package upgrade (%s => %s)\n"), + alpm_pkg_get_name(local), alpm_pkg_get_version(local), + alpm_pkg_get_version(spkg)); + continue; + } - pmpkg_t *tmp = _alpm_pkg_dup(local); - if(tmp == NULL) { - pm_errno = PM_ERR_MEMORY; - synclist_free(*syncpkgs); - return(-1); - } - sync = _alpm_sync_new(PM_SYNC_TYPE_UPGRADE, spkg, tmp); - if(sync == NULL) { - _alpm_pkg_free(tmp); - pm_errno = PM_ERR_MEMORY; - synclist_free(*syncpkgs); - return(-1); - } - *syncpkgs = alpm_list_add(*syncpkgs, sync); + /* add the upgrade package to our pmsyncpkg_t list */ + if(_alpm_sync_find(*syncpkgs, alpm_pkg_get_name(spkg))) { + /* avoid duplicated targets */ + continue; + } + /* we can set any reason here, it will be overridden by add_commit */ + pmsyncpkg_t *sync = _alpm_sync_new(PM_PKG_REASON_EXPLICIT, spkg, NULL); + if(sync == NULL) { + alpm_list_free_inner(*syncpkgs, (alpm_list_fn_free)_alpm_sync_free); + alpm_list_free(*syncpkgs); + *syncpkgs = NULL; + alpm_list_free(replaced); + return(-1); } + *syncpkgs = alpm_list_add(*syncpkgs, sync); } } + alpm_list_free(replaced); return(0); } int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync, char *name) { - char targline[PKG_FULLNAME_LEN]; + char *targline; char *targ; alpm_list_t *j; pmpkg_t *local; @@ -287,8 +281,8 @@ int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sy ASSERT(db_local != NULL, RET_ERR(PM_ERR_DB_NULL, -1)); ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1)); ASSERT(name != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1)); + STRDUP(targline, name, RET_ERR(PM_ERR_MEMORY, -1)); - strncpy(targline, name, PKG_FULLNAME_LEN); targ = strchr(targline, '/'); if(targ) { /* we are looking for a package in a specific database */ @@ -301,13 +295,15 @@ int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sy repo_found = 1; spkg = _alpm_db_get_pkgfromcache(db, targ); if(spkg == NULL) { - RET_ERR(PM_ERR_PKG_NOT_FOUND, -1); + pm_errno = PM_ERR_PKG_NOT_FOUND; + goto error; } } } if(!repo_found) { _alpm_log(PM_LOG_ERROR, _("repository '%s' not found\n"), targline); - RET_ERR(PM_ERR_PKG_REPO_NOT_FOUND, -1); + pm_errno = PM_ERR_PKG_REPO_NOT_FOUND; + goto error; } } else { targ = targline; @@ -316,10 +312,16 @@ int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sy spkg = _alpm_db_get_pkgfromcache(db, targ); } if(spkg == NULL) { - RET_ERR(PM_ERR_PKG_NOT_FOUND, -1); + pm_errno = PM_ERR_PKG_NOT_FOUND; + goto error; } } + if(_alpm_sync_find(trans->packages, alpm_pkg_get_name(spkg))) { + FREE(targline); + RET_ERR(PM_ERR_TRANS_DUP_TARGET, -1); + } + if(_alpm_pkg_should_ignore(spkg)) { int resp; QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, spkg, NULL, NULL, &resp); @@ -346,39 +348,80 @@ int _alpm_sync_addtarget(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sy } /* add the package to the transaction */ - if(!_alpm_sync_find(trans->packages, alpm_pkg_get_name(spkg))) { - pmpkg_t *dummy = NULL; - if(local) { - dummy = _alpm_pkg_dup(local); - if(dummy == NULL) { - RET_ERR(PM_ERR_MEMORY, -1); - } - } - sync = _alpm_sync_new(PM_SYNC_TYPE_UPGRADE, spkg, dummy); - if(sync == NULL) { - _alpm_pkg_free(dummy); - RET_ERR(PM_ERR_MEMORY, -1); - } - _alpm_log(PM_LOG_DEBUG, "adding target '%s' to the transaction set\n", - alpm_pkg_get_name(spkg)); - trans->packages = alpm_list_add(trans->packages, sync); + sync = _alpm_sync_new(PM_PKG_REASON_EXPLICIT, spkg, NULL); + if(sync == NULL) { + goto error; } + _alpm_log(PM_LOG_DEBUG, "adding target '%s' to the transaction set\n", + alpm_pkg_get_name(spkg)); + trans->packages = alpm_list_add(trans->packages, sync); + FREE(targline); return(0); + +error: + if(targline) { + FREE(targline); + } + return(-1); } /* Helper functions for alpm_list_remove - */ +*/ static int syncpkg_cmp(const void *s1, const void *s2) { const pmsyncpkg_t *sp1 = s1; const pmsyncpkg_t *sp2 = s2; - pmpkg_t *p1, *p2; + pmpkg_t *p1 = alpm_sync_get_pkg(sp1); + pmpkg_t *p2 = alpm_sync_get_pkg(sp2); + return(strcmp(alpm_pkg_get_name(p1), alpm_pkg_get_name(p2))); +} - p1 = alpm_sync_get_pkg(sp1); - p2 = alpm_sync_get_pkg(sp2); +/** Compute the size of the files that will be downloaded to install a + * package. + * @param newpkg the new package to upgrade to + */ +static int compute_download_size(pmpkg_t *newpkg) +{ + const char *fname; + char *fpath; + unsigned long size = 0; - return(strcmp(alpm_pkg_get_name(p1), alpm_pkg_get_name(p2))); + fname = alpm_pkg_get_filename(newpkg); + ASSERT(fname != NULL, RET_ERR(PM_ERR_PKG_INVALID_NAME, -1)); + fpath = _alpm_filecache_find(fname); + + if(fpath) { + FREE(fpath); + size = 0; + } else if(handle->usedelta) { + unsigned long dltsize; + unsigned long pkgsize = alpm_pkg_get_size(newpkg); + + dltsize = _alpm_shortest_delta_path( + alpm_pkg_get_deltas(newpkg), + alpm_pkg_get_filename(newpkg), + alpm_pkg_get_md5sum(newpkg), + &newpkg->delta_path); + + if(newpkg->delta_path && (dltsize < pkgsize * MAX_DELTA_RATIO)) { + _alpm_log(PM_LOG_DEBUG, "using delta size\n"); + size = dltsize; + } else { + _alpm_log(PM_LOG_DEBUG, "using package size\n"); + size = alpm_pkg_get_size(newpkg); + alpm_list_free(newpkg->delta_path); + newpkg->delta_path = NULL; + } + } else { + size = alpm_pkg_get_size(newpkg); + } + + _alpm_log(PM_LOG_DEBUG, "setting download size %ld for pkg %s\n", size, + alpm_pkg_get_name(newpkg)); + + newpkg->download_size = size; + return(0); } int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync, alpm_list_t **data) @@ -397,14 +440,15 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync *data = NULL; } - if(!(trans->flags & PM_TRANS_FLAG_DEPENDSONLY)) { - for(i = trans->packages; i; i = i->next) { - pmsyncpkg_t *sync = i->data; - list = alpm_list_add(list, sync->pkg); - } + for(i = trans->packages; i; i = i->next) { + pmsyncpkg_t *sync = i->data; + list = alpm_list_add(list, sync->pkg); } if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) { + /* store a pointer to the last original target so we can tell what was + * pulled by resolvedeps */ + alpm_list_t *pulled = alpm_list_last(list); /* Resolve targets dependencies */ EVENT(trans, PM_TRANS_EVT_RESOLVEDEPS_START, NULL, NULL); _alpm_log(PM_LOG_DEBUG, "resolving target's dependencies\n"); @@ -412,10 +456,8 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync /* build remove list for resolvedeps */ for(i = trans->packages; i; i = i->next) { pmsyncpkg_t *sync = i->data; - if(sync->type == PM_SYNC_TYPE_REPLACE) { - for(j = sync->data; j; j = j->next) { - remove = alpm_list_add(remove, j->data); - } + for(j = sync->removes; j; j = j->next) { + remove = alpm_list_add(remove, j->data); } } @@ -429,33 +471,27 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync } } - if((trans->flags & PM_TRANS_FLAG_DEPENDSONLY)) { - FREELIST(trans->packages); - } - - for(i = list; i; i = i->next) { - /* add the dependencies found by resolvedeps to the transaction set */ + for(i = pulled->next; i; i = i->next) { pmpkg_t *spkg = i->data; - if(!_alpm_sync_find(trans->packages, alpm_pkg_get_name(spkg))) { - pmsyncpkg_t *sync = _alpm_sync_new(PM_SYNC_TYPE_DEPEND, spkg, NULL); - if(sync == NULL) { - ret = -1; - goto cleanup; - } - trans->packages = alpm_list_add(trans->packages, sync); - _alpm_log(PM_LOG_DEBUG, "adding package %s-%s to the transaction targets\n", - alpm_pkg_get_name(spkg), alpm_pkg_get_version(spkg)); + pmsyncpkg_t *sync = _alpm_sync_new(PM_PKG_REASON_DEPEND, spkg, NULL); + if(sync == NULL) { + ret = -1; + goto cleanup; } + trans->packages = alpm_list_add(trans->packages, sync); + _alpm_log(PM_LOG_DEBUG, "adding package %s-%s to the transaction targets\n", + alpm_pkg_get_name(spkg), alpm_pkg_get_version(spkg)); } /* re-order w.r.t. dependencies */ - alpm_list_t *sortlist = _alpm_sortbydeps(list, PM_TRANS_TYPE_ADD); + alpm_list_t *sortlist = _alpm_sortbydeps(list, 0); alpm_list_t *newpkgs = NULL; for(i = sortlist; i; i = i->next) { for(j = trans->packages; j; j = j->next) { pmsyncpkg_t *s = j->data; if(s->pkg == i->data) { newpkgs = alpm_list_add(newpkgs, s); + break; } } } @@ -472,180 +508,130 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync EVENT(trans, PM_TRANS_EVT_INTERCONFLICTS_START, NULL, NULL); _alpm_log(PM_LOG_DEBUG, "looking for conflicts\n"); - deps = _alpm_checkconflicts(db_local, list); - if(deps) { - int errorout = 0; - alpm_list_t *asked = NULL; - pmconflict_t *conflict = NULL; - - for(i = deps; i && !errorout; i = i->next) { - pmsyncpkg_t *sync; - pmpkg_t *found = NULL; - - conflict = i->data; - _alpm_log(PM_LOG_DEBUG, "package '%s' conflicts with '%s'\n", - conflict->package1, conflict->package2); - /* check if the conflicting package is about to be removed/replaced. - * if so, then just ignore it. */ - for(j = trans->packages; j && !found; j = j->next) { - sync = j->data; - if(sync->type == PM_SYNC_TYPE_REPLACE) { - found = _alpm_pkg_find(conflict->package2, sync->data); - } - } - if(found) { - _alpm_log(PM_LOG_DEBUG, "'%s' is already elected for removal -- skipping\n", - alpm_pkg_get_name(found)); - continue; - } - sync = _alpm_sync_find(trans->packages, conflict->package1); - if(sync == NULL) { - _alpm_log(PM_LOG_DEBUG, "'%s' not found in transaction set -- skipping\n", - conflict->package1); - continue; - } - pmpkg_t *local = _alpm_db_get_pkgfromcache(db_local, conflict->package2); - /* check if this package provides the package it's conflicting with */ - if(alpm_list_find(alpm_pkg_get_provides(sync->pkg), - conflict->package2, _alpm_prov_cmp)) { - /* treat like a replaces item so requiredby fields are - * inherited properly. */ - _alpm_log(PM_LOG_DEBUG, "package '%s' provides its own conflict\n", - conflict->package1); - if(!local) { - char *rmpkg = NULL; - void *target, *depend; - /* hmmm, package2 isn't installed, so it must be conflicting - * with another package in our final list. For example: - * - * pacman -S blackbox xfree86 - * - * If no x-servers are installed and blackbox pulls in xorg, then - * xorg and xfree86 will conflict with each other. In this case, - * we should follow the user's preference and rip xorg out of final, - * opting for xfree86 instead. - */ - - /* figure out which one was requested in targets. If they both - * were, then it's still an unresolvable conflict. */ - target = alpm_list_find_str(trans->targets, conflict->package1); - depend = alpm_list_find_str(trans->targets, conflict->package2); - if(depend && !target) { - _alpm_log(PM_LOG_DEBUG, "'%s' is in the target list -- keeping it\n", - conflict->package2); - /* remove conflict->package1 */ - rmpkg = conflict->package1; - } else if(target && !depend) { - _alpm_log(PM_LOG_DEBUG, "'%s' is in the target list -- keeping it\n", - conflict->package1); - /* remove conflict->package2 */ - rmpkg = conflict->package2; - } else { - /* miss->target2 is not needed, miss->target already provides - * it, let's resolve the conflict */ - rmpkg = conflict->package2; - } - if(rmpkg) { - pmsyncpkg_t *rsync = _alpm_sync_find(trans->packages, rmpkg); - if(rsync) { - void *vpkg; - _alpm_log(PM_LOG_DEBUG, "removing '%s' from target list\n", - rsync->pkg->name); - trans->packages = alpm_list_remove(trans->packages, rsync, - syncpkg_cmp, &vpkg); - _alpm_sync_free(vpkg); - } - continue; - } + /* 1. check for conflicts in the target list */ + _alpm_log(PM_LOG_DEBUG, "check targets vs targets\n"); + deps = _alpm_innerconflicts(list); + + for(i = deps; i; i = i->next) { + pmconflict_t *conflict = i->data; + pmsyncpkg_t *rsync, *sync, *sync1, *sync2; + + /* have we already removed one of the conflicting targets? */ + sync1 = _alpm_sync_find(trans->packages, conflict->package1); + sync2 = _alpm_sync_find(trans->packages, conflict->package2); + if(!sync1 || !sync2) { + continue; + } + + _alpm_log(PM_LOG_DEBUG, "conflicting packages in the sync list: '%s' <-> '%s'\n", + conflict->package1, conflict->package2); + + /* if sync1 provides sync2, we remove sync2 from the targets, and vice versa */ + pmdepend_t *dep1 = _alpm_splitdep(conflict->package1); + pmdepend_t *dep2 = _alpm_splitdep(conflict->package2); + if(alpm_depcmp(sync1->pkg, dep2)) { + rsync = sync2; + sync = sync1; + } else if(alpm_depcmp(sync2->pkg, dep1)) { + rsync = sync1; + sync = sync2; + } else { + _alpm_log(PM_LOG_ERROR, _("unresolvable package conflicts detected\n")); + pm_errno = PM_ERR_CONFLICTING_DEPS; + ret = -1; + if(data) { + pmconflict_t *newconflict = _alpm_conflict_dup(conflict); + if(newconflict) { + *data = alpm_list_add(*data, newconflict); } } - /* It's a conflict -- see if they want to remove it */ - _alpm_log(PM_LOG_DEBUG, "resolving package '%s' conflict\n", - conflict->package1); - if(local) { - int doremove = 0; - if(!alpm_list_find_str(asked, conflict->package2)) { - QUESTION(trans, PM_TRANS_CONV_CONFLICT_PKG, conflict->package1, - conflict->package2, NULL, &doremove); - asked = alpm_list_add(asked, strdup(conflict->package2)); - if(doremove) { - pmpkg_t *q = _alpm_pkg_dup(local); - if(sync->type != PM_SYNC_TYPE_REPLACE) { - /* switch this sync type to REPLACE */ - sync->type = PM_SYNC_TYPE_REPLACE; - _alpm_pkg_free(sync->data); - sync->data = NULL; - } - /* append to the replaces list */ - _alpm_log(PM_LOG_DEBUG, "electing '%s' for removal\n", - conflict->package2); - sync->data = alpm_list_add(sync->data, q); - /* see if the package is in the current target list */ - pmsyncpkg_t *rsync = _alpm_sync_find(trans->packages, - conflict->package2); - if(rsync) { - /* remove it from the target list */ - void *vpkg; - _alpm_log(PM_LOG_DEBUG, "removing '%s' from target list\n", - conflict->package2); - trans->packages = alpm_list_remove(trans->packages, rsync, - syncpkg_cmp, &vpkg); - _alpm_sync_free(vpkg); - } - } else { - /* abort */ - _alpm_log(PM_LOG_ERROR, _("unresolvable package conflicts detected\n")); - errorout = 1; - } - } - } else { - _alpm_log(PM_LOG_ERROR, _("unresolvable package conflicts detected\n")); - errorout = 1; + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); + alpm_list_free(deps); + _alpm_dep_free(dep1); + _alpm_dep_free(dep2); + goto cleanup; + } + _alpm_dep_free(dep1); + _alpm_dep_free(dep2); + + /* Prints warning */ + _alpm_log(PM_LOG_WARNING, + _("removing '%s' from target list because it conflicts with '%s'\n"), + rsync->pkg->name, sync->pkg->name); + void *vpkg; + trans->packages = alpm_list_remove(trans->packages, rsync, + syncpkg_cmp, &vpkg); + pmsyncpkg_t *syncpkg = vpkg; + list = alpm_list_remove(list, syncpkg->pkg, _alpm_pkg_cmp, NULL); + _alpm_sync_free(syncpkg); + continue; + } + + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); + alpm_list_free(deps); + deps = NULL; + + /* 2. we check for target vs db conflicts (and resolve)*/ + _alpm_log(PM_LOG_DEBUG, "check targets vs db and db vs targets\n"); + deps = _alpm_outerconflicts(db_local, list); + + for(i = deps; i; i = i->next) { + pmconflict_t *conflict = i->data; + + /* if conflict->package2 (the local package) is not elected for removal, + we ask the user */ + int found = 0; + for(j = trans->packages; j && !found; j = j->next) { + pmsyncpkg_t *sync = j->data; + if(_alpm_pkg_find(sync->removes, conflict->package2)) { + found = 1; } } - if(errorout) { - /* The last conflict was unresolvable, so we duplicate it and add it to *data */ + if(found) { + continue; + } + + _alpm_log(PM_LOG_DEBUG, "package '%s' conflicts with '%s'\n", + conflict->package1, conflict->package2); + + pmsyncpkg_t *sync = _alpm_sync_find(trans->packages, conflict->package1); + pmpkg_t *local = _alpm_db_get_pkgfromcache(db_local, conflict->package2); + int doremove = 0; + QUESTION(trans, PM_TRANS_CONV_CONFLICT_PKG, conflict->package1, + conflict->package2, NULL, &doremove); + if(doremove) { + /* append to the removes list */ + _alpm_log(PM_LOG_DEBUG, "electing '%s' for removal\n", conflict->package2); + sync->removes = alpm_list_add(sync->removes, local); + } else { /* abort */ + _alpm_log(PM_LOG_ERROR, _("unresolvable package conflicts detected\n")); pm_errno = PM_ERR_CONFLICTING_DEPS; + ret = -1; if(data) { - pmconflict_t *lastconflict = conflict; - if((conflict = malloc(sizeof(pmconflict_t))) == NULL) { - _alpm_log(PM_LOG_ERROR, _("malloc failure: could not allocate %zd bytes\n"), - sizeof(pmconflict_t)); - FREELIST(*data); - pm_errno = PM_ERR_MEMORY; - } else { - *conflict = *lastconflict; - *data = alpm_list_add(*data, conflict); + pmconflict_t *newconflict = _alpm_conflict_dup(conflict); + if(newconflict) { + *data = alpm_list_add(*data, newconflict); } } - FREELIST(asked); - FREELIST(deps); - ret = -1; + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); + alpm_list_free(deps); goto cleanup; } - FREELIST(asked); - FREELIST(deps); } EVENT(trans, PM_TRANS_EVT_INTERCONFLICTS_DONE, NULL, NULL); + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_conflict_free); + alpm_list_free(deps); } if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) { - /* rebuild remove and list */ - alpm_list_free(list); - list = NULL; - for(i = trans->packages; i; i = i->next) { - pmsyncpkg_t *sync = i->data; - list = alpm_list_add(list, sync->pkg); - } + /* rebuild remove list */ alpm_list_free(remove); remove = NULL; for(i = trans->packages; i; i = i->next) { pmsyncpkg_t *sync = i->data; - if(sync->type == PM_SYNC_TYPE_REPLACE) { - for(j = sync->data; j; j = j->next) { - remove = alpm_list_add(remove, j->data); - } + for(j = sync->removes; j; j = j->next) { + remove = alpm_list_add(remove, j->data); } } @@ -657,11 +643,20 @@ int _alpm_sync_prepare(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t *dbs_sync if(data) { *data = deps; } else { - FREELIST(deps); + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free); + alpm_list_free(deps); } goto cleanup; } } + for(i = list; i; i = i->next) { + /* update download size field */ + pmpkg_t *spkg = i->data; + if(compute_download_size(spkg) != 0) { + ret = -1; + goto cleanup; + } + } cleanup: alpm_list_free(list); @@ -670,86 +665,14 @@ cleanup: return(ret); } -/** Returns a list of deltas that should be downloaded instead of the - * package. - * - * It first tests if a delta path exists between the currently installed - * version (if any) and the version to upgrade to. If so, the delta path - * is used if its size is below a set percentage (MAX_DELTA_RATIO) of - * the package size, Otherwise, an empty list is returned. - * - * @param newpkg the new package to upgrade to - * @param db_local the local database - * - * @return the list of pmdelta_t * objects. NULL (the empty list) is - * returned if the package should be downloaded instead of deltas. - */ -static alpm_list_t *pkg_upgrade_delta_path(pmpkg_t *newpkg, pmdb_t *db_local) -{ - pmpkg_t *oldpkg = alpm_db_get_pkg(db_local, newpkg->name); - alpm_list_t *ret = NULL; - - if(oldpkg) { - const char *oldname = alpm_pkg_get_filename(oldpkg); - char *oldpath = _alpm_filecache_find(oldname); - - if(oldpath) { - alpm_list_t *deltas = _alpm_shortest_delta_path( - alpm_pkg_get_deltas(newpkg), - alpm_pkg_get_version(oldpkg), - alpm_pkg_get_version(newpkg)); - - if(deltas) { - unsigned long dltsize = _alpm_delta_path_size(deltas); - unsigned long pkgsize = alpm_pkg_get_size(newpkg); - - if(dltsize < pkgsize * MAX_DELTA_RATIO) { - ret = deltas; - } else { - ret = NULL; - alpm_list_free(deltas); - } - } - - FREE(oldpath); - } - } - - return(ret); -} - /** Returns the size of the files that will be downloaded to install a * package. - * * @param newpkg the new package to upgrade to - * @param db_local the local database - * * @return the size of the download */ -unsigned long SYMEXPORT alpm_pkg_download_size(pmpkg_t *newpkg, pmdb_t *db_local) +unsigned long SYMEXPORT alpm_pkg_download_size(pmpkg_t *newpkg) { - char *fpath = _alpm_filecache_find(alpm_pkg_get_filename(newpkg)); - unsigned long size = 0; - - if(fpath) { - size = 0; - } else if(handle->usedelta) { - alpm_list_t *deltas = pkg_upgrade_delta_path(newpkg, db_local); - - if(deltas) { - size = _alpm_delta_path_size_uncached(deltas); - } else { - size = alpm_pkg_get_size(newpkg); - } - - alpm_list_free(deltas); - } else { - size = alpm_pkg_get_size(newpkg); - } - - FREE(fpath); - - return(size); + return(newpkg->download_size); } /** Applies delta files to create an upgraded package file. @@ -758,88 +681,82 @@ unsigned long SYMEXPORT alpm_pkg_download_size(pmpkg_t *newpkg, pmdb_t *db_local * ending package files. * * @param trans the transaction - * @param patches A list of alternating pmpkg_t * and pmdelta_t * - * objects. The patch command will be built using the pmpkg_t, pmdelta_t - * pair. * * @return 0 if all delta files were able to be applied, 1 otherwise. */ -static int apply_deltas(pmtrans_t *trans, alpm_list_t *patches) +static int apply_deltas(pmtrans_t *trans) { - /* keep track of the previous package in the loop to decide if a - * package file should be deleted */ - pmpkg_t *lastpkg = NULL; - int lastpkg_failed = 0; + alpm_list_t *i; int ret = 0; const char *cachedir = _alpm_filecache_setup(); - alpm_list_t *p = patches; - while(p) { - pmpkg_t *pkg; - pmdelta_t *d; - char command[PATH_MAX], fname[PATH_MAX]; - char pkgfilename[PKG_FILENAME_LEN]; + for(i = trans->packages; i; i = i->next) { + pmsyncpkg_t *sync = i->data; + pmpkg_t *spkg = sync->pkg; + alpm_list_t *delta_path = spkg->delta_path; + alpm_list_t *dlts = NULL; - pkg = alpm_list_getdata(p); - p = alpm_list_next(p); + if(!delta_path) { + continue; + } - d = alpm_list_getdata(p); - p = alpm_list_next(p); + for(dlts = delta_path; dlts; dlts = dlts->next) { + pmdelta_t *d = dlts->data; + char *delta, *from, *to; + char command[PATH_MAX]; + int len = 0; - /* if patching fails, ignore the rest of that package's deltas */ - if(lastpkg_failed) { - if(pkg == lastpkg) { - continue; + delta = _alpm_filecache_find(d->delta); + /* the initial package might be in a different cachedir */ + if(dlts == delta_path) { + from = _alpm_filecache_find(d->from); } else { - lastpkg_failed = 0; + /* len = cachedir len + from len + '/' + null */ + len = strlen(cachedir) + strlen(d->from) + 2; + CALLOC(from, len, sizeof(char), RET_ERR(PM_ERR_MEMORY, 1)); + snprintf(from, len, "%s/%s", cachedir, d->from); } - } + len = strlen(cachedir) + strlen(d->to) + 2; + CALLOC(to, len, sizeof(char), RET_ERR(PM_ERR_MEMORY, 1)); + snprintf(to, len, "%s/%s", cachedir, d->to); - /* an example of the patch command: (using /cache for cachedir) - * xdelta patch /cache/pacman_3.0.0-1_to_3.0.1-1-i686.delta \ - * /cache/pacman-3.0.0-1-i686.pkg.tar.gz \ - * /cache/pacman-3.0.1-1-i686.pkg.tar.gz - */ - - /* build the patch command */ - snprintf(command, PATH_MAX, - "xdelta patch" /* the command */ - " %s/%s" /* the delta */ - " %s/%s-%s-%s" PKGEXT /* the 'from' package */ - " %s/%s-%s-%s" PKGEXT, /* the 'to' package */ - cachedir, d->filename, - cachedir, pkg->name, d->from, pkg->arch, - cachedir, pkg->name, d->to, pkg->arch); - - _alpm_log(PM_LOG_DEBUG, _("command: %s\n"), command); - - snprintf(pkgfilename, PKG_FILENAME_LEN, "%s-%s-%s" PKGEXT, - pkg->name, d->to, pkg->arch); - - EVENT(trans, PM_TRANS_EVT_DELTA_PATCH_START, pkgfilename, d->filename); - - if(system(command) == 0) { - EVENT(trans, PM_TRANS_EVT_DELTA_PATCH_DONE, NULL, NULL); - - /* delete the delta file */ - snprintf(fname, PATH_MAX, "%s/%s", cachedir, d->filename); - unlink(fname); - - /* Delete the 'from' package but only if it is an intermediate - * package. The starting 'from' package should be kept, just - * as if deltas were not used. Delete the package file if the - * previous iteration of the loop used the same package. */ - if(pkg == lastpkg) { - snprintf(fname, PATH_MAX, "%s/%s-%s-%s" PKGEXT, - cachedir, pkg->name, d->from, pkg->arch); - unlink(fname); - } else { - lastpkg = pkg; + /* an example of the patch command: (using /cache for cachedir) + * xdelta patch /path/to/pacman_3.0.0-1_to_3.0.1-1-i686.delta \ + * /path/to/pacman-3.0.0-1-i686.pkg.tar.gz \ + * /cache/pacman-3.0.1-1-i686.pkg.tar.gz + */ + + /* build the patch command */ + snprintf(command, PATH_MAX, "xdelta patch %s %s %s", delta, from, to); + + _alpm_log(PM_LOG_DEBUG, _("command: %s\n"), command); + + EVENT(trans, PM_TRANS_EVT_DELTA_PATCH_START, d->to, d->delta); + + int retval = system(command); + if(retval == 0) { + EVENT(trans, PM_TRANS_EVT_DELTA_PATCH_DONE, NULL, NULL); + + /* delete the delta file */ + unlink(delta); + + /* Delete the 'from' package but only if it is an intermediate + * package. The starting 'from' package should be kept, just + * as if deltas were not used. */ + if(dlts != delta_path) { + unlink(from); + } + } + FREE(from); + FREE(to); + FREE(delta); + + if(retval != 0) { + /* one delta failed for this package, cancel the remaining ones */ + EVENT(trans, PM_TRANS_EVT_DELTA_PATCH_FAILED, NULL, NULL); + ret = 1; + break; } - } else { - EVENT(trans, PM_TRANS_EVT_DELTA_PATCH_FAILED, NULL, NULL); - lastpkg_failed = 1; - ret = 1; } } @@ -854,107 +771,29 @@ static int apply_deltas(pmtrans_t *trans, alpm_list_t *patches) * @param trans the transaction * @param filename the filename of the file to test * @param md5sum the expected md5sum of the file - * @param data data to write the error messages to * - * @return 0 if the md5sum matched, 1 otherwise + * @return 0 if the md5sum matched, 1 if not, -1 in case of errors */ static int test_md5sum(pmtrans_t *trans, const char *filename, - const char *md5sum, alpm_list_t **data) + const char *md5sum) { char *filepath; - char *md5sum2; - char *errormsg = NULL; - int ret = 0; + int ret; filepath = _alpm_filecache_find(filename); - md5sum2 = alpm_get_md5sum(filepath); - if(md5sum == NULL) { - if(data) { - /* TODO wtf is this? malloc'd strings for error messages? */ - if((errormsg = calloc(512, sizeof(char))) == NULL) { - RET_ERR(PM_ERR_MEMORY, -1); - } - snprintf(errormsg, 512, _("can't get md5 checksum for file %s\n"), - filename); - *data = alpm_list_add(*data, errormsg); - } - ret = 1; - } else if(md5sum2 == NULL) { - if(data) { - if((errormsg = calloc(512, sizeof(char))) == NULL) { - RET_ERR(PM_ERR_MEMORY, -1); - } - snprintf(errormsg, 512, _("can't get md5 checksum for file %s\n"), - filename); - *data = alpm_list_add(*data, errormsg); - } - ret = 1; - } else if(strcmp(md5sum, md5sum2) != 0) { + ret = _alpm_test_md5sum(filepath, md5sum); + + if(ret == 1) { int doremove = 0; QUESTION(trans, PM_TRANS_CONV_CORRUPTED_PKG, (char *)filename, NULL, NULL, &doremove); if(doremove) { unlink(filepath); } - if(data) { - if((errormsg = calloc(512, sizeof(char))) == NULL) { - RET_ERR(PM_ERR_MEMORY, -1); - } - snprintf(errormsg, 512, _("file %s was corrupted (bad MD5 checksum)\n"), - filename); - *data = alpm_list_add(*data, errormsg); - } - ret = 1; } FREE(filepath); - FREE(md5sum2); - - return(ret); -} - -/** Compares the md5sum of a delta to the expected value. - * - * @param trans the transaction - * @param delta the delta to test - * @param data data to write the error messages to - * - * @return 0 if the md5sum matched, 1 otherwise - */ -static int test_delta_md5sum(pmtrans_t *trans, pmdelta_t *delta, - alpm_list_t **data) -{ - const char *filename; - const char *md5sum; - int ret = 0; - - filename = alpm_delta_get_filename(delta); - md5sum = alpm_delta_get_md5sum(delta); - - ret = test_md5sum(trans, filename, md5sum, data); - - return(ret); -} - -/** Compares the md5sum of a package to the expected value. - * - * @param trans the transaction - * @param pkg the package to test - * @param data data to write the error messages to - * - * @return 0 if the md5sum matched, 1 otherwise - */ -static int test_pkg_md5sum(pmtrans_t *trans, pmpkg_t *pkg, alpm_list_t **data) -{ - const char *filename; - const char *md5sum; - int ret = 0; - - filename = alpm_pkg_get_filename(pkg); - md5sum = alpm_pkg_get_md5sum(pkg); - - ret = test_md5sum(trans, filename, md5sum, data); return(ret); } @@ -962,11 +801,12 @@ static int test_pkg_md5sum(pmtrans_t *trans, pmpkg_t *pkg, alpm_list_t **data) int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) { alpm_list_t *i, *j, *files = NULL; - alpm_list_t *patches = NULL, *deltas = NULL; + alpm_list_t *deltas = NULL; pmtrans_t *tr = NULL; - int replaces = 0, retval = 0; + int replaces = 0; + int errors = 0; const char *cachedir = NULL; - int dltotal = 0, dl = 0; + int ret = -1; ALPM_LOG_FUNC; @@ -976,14 +816,6 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) cachedir = _alpm_filecache_setup(); trans->state = STATE_DOWNLOADING; - /* Sum up the download sizes. This has to be in its own loop because - * the download loop is grouped by db. */ - for(j = trans->packages; j; j = j->next) { - pmsyncpkg_t *sync = j->data; - pmpkg_t *spkg = sync->pkg; - dltotal += alpm_pkg_download_size(spkg, db_local); - } - /* group sync records by repository and download */ for(i = handle->dbs_sync; i; i = i->next) { pmdb_t *current = i->data; @@ -997,60 +829,45 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) const char *fname = NULL; fname = alpm_pkg_get_filename(spkg); + ASSERT(fname != NULL, RET_ERR(PM_ERR_PKG_INVALID_NAME, -1)); if(trans->flags & PM_TRANS_FLAG_PRINTURIS) { EVENT(trans, PM_TRANS_EVT_PRINTURI, (char *)alpm_db_get_url(current), (char *)fname); } else { - char *fpath = _alpm_filecache_find(fname); - if(!fpath) { - if(handle->usedelta) { - alpm_list_t *delta_path = pkg_upgrade_delta_path(spkg, db_local); - - if(delta_path) { - alpm_list_t *dlts = NULL; - - for(dlts = delta_path; dlts; dlts = alpm_list_next(dlts)) { - pmdelta_t *d = (pmdelta_t *)alpm_list_getdata(dlts); - char *fpath2 = _alpm_filecache_find(d->filename); - - if(!fpath2) { - /* add the delta filename to the download list if - * it's not in the cache*/ - files = alpm_list_add(files, strdup(d->filename)); - } - - /* save the package and delta so that the xdelta patch - * command can be run after the downloads finish */ - patches = alpm_list_add(patches, spkg); - patches = alpm_list_add(patches, d); - - /* keep a list of the delta files for md5sums */ - deltas = alpm_list_add(deltas, d); + if(spkg->download_size != 0) { + alpm_list_t *delta_path = spkg->delta_path; + if(delta_path) { + alpm_list_t *dlts = NULL; + + for(dlts = delta_path; dlts; dlts = dlts->next) { + pmdelta_t *d = dlts->data; + + if(d->download_size != 0) { + /* add the delta filename to the download list if + * it's not in the cache */ + files = alpm_list_add(files, strdup(d->delta)); } - alpm_list_free(delta_path); - delta_path = NULL; - } else { - /* no deltas to download, so add the file to the - * download list */ - files = alpm_list_add(files, strdup(fname)); + /* keep a list of the delta files for md5sums */ + deltas = alpm_list_add(deltas, d); } + } else { /* not using deltas, so add the file to the download list */ files = alpm_list_add(files, strdup(fname)); } } - FREE(fpath); } } } if(files) { EVENT(trans, PM_TRANS_EVT_RETRIEVE_START, current->treename, NULL); - if(_alpm_downloadfiles(current->servers, cachedir, files, &dl, dltotal)) { + if(_alpm_download_files(files, current->servers, cachedir)) { _alpm_log(PM_LOG_WARNING, _("failed to retrieve some files from %s\n"), current->treename); - RET_ERR(PM_ERR_RETRIEVE, -1); + pm_errno = PM_ERR_RETRIEVE; + goto error; } FREELIST(files); } @@ -1064,35 +881,31 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) /* only output if there are deltas to work with */ if(deltas) { + errors = 0; /* Check integrity of deltas */ EVENT(trans, PM_TRANS_EVT_DELTA_INTEGRITY_START, NULL, NULL); for(i = deltas; i; i = i->next) { pmdelta_t *d = alpm_list_getdata(i); + const char *filename = alpm_delta_get_filename(d); + const char *md5sum = alpm_delta_get_md5sum(d); - ret = test_delta_md5sum(trans, d, data); - - if(ret == 1) { - retval = 1; - } else if(ret == -1) { /* -1 is for serious errors */ - RET_ERR(pm_errno, -1); + if(test_md5sum(trans, filename, md5sum) != 0) { + errors++; + *data = alpm_list_add(*data, strdup(filename)); } } - if(retval) { - pm_errno = PM_ERR_DLT_CORRUPTED; + if(errors) { + pm_errno = PM_ERR_DLT_INVALID; goto error; } EVENT(trans, PM_TRANS_EVT_DELTA_INTEGRITY_DONE, NULL, NULL); /* Use the deltas to generate the packages */ EVENT(trans, PM_TRANS_EVT_DELTA_PATCHES_START, NULL, NULL); - ret = apply_deltas(trans, patches); + ret = apply_deltas(trans); EVENT(trans, PM_TRANS_EVT_DELTA_PATCHES_DONE, NULL, NULL); - alpm_list_free(patches); - patches = NULL; - alpm_list_free(deltas); - deltas = NULL; } if(ret) { pm_errno = PM_ERR_DLT_PATCHFAILED; @@ -1103,21 +916,20 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) /* Check integrity of packages */ EVENT(trans, PM_TRANS_EVT_INTEGRITY_START, NULL, NULL); + errors = 0; for(i = trans->packages; i; i = i->next) { pmsyncpkg_t *sync = i->data; pmpkg_t *spkg = sync->pkg; - int ret = 0; + const char *filename = alpm_pkg_get_filename(spkg); + const char *md5sum = alpm_pkg_get_md5sum(spkg); - ret = test_pkg_md5sum(trans, spkg, data); - - if(ret == 1) { - retval = 1; - } else if(ret == -1) { /* -1 is for serious errors */ - RET_ERR(pm_errno, -1); + if(test_md5sum(trans, filename, md5sum) != 0) { + errors++; + *data = alpm_list_add(*data, strdup(filename)); } } - if(retval) { - pm_errno = PM_ERR_PKG_CORRUPTED; + if(errors) { + pm_errno = PM_ERR_PKG_INVALID; goto error; } EVENT(trans, PM_TRANS_EVT_INTEGRITY_DONE, NULL, NULL); @@ -1130,7 +942,6 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) tr = _alpm_trans_new(); if(tr == NULL) { _alpm_log(PM_LOG_ERROR, _("could not create removal transaction\n")); - pm_errno = PM_ERR_MEMORY; goto error; } @@ -1141,16 +952,14 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) for(i = trans->packages; i; i = i->next) { pmsyncpkg_t *sync = i->data; - if(sync->type == PM_SYNC_TYPE_REPLACE) { - alpm_list_t *j; - for(j = sync->data; j; j = j->next) { - pmpkg_t *pkg = j->data; - if(!_alpm_pkg_find(pkg->name, tr->packages)) { - if(_alpm_trans_addtarget(tr, pkg->name) == -1) { - goto error; - } - replaces++; + alpm_list_t *j; + for(j = sync->removes; j; j = j->next) { + pmpkg_t *pkg = j->data; + if(!_alpm_pkg_find(tr->packages, pkg->name)) { + if(_alpm_trans_addtarget(tr, pkg->name) == -1) { + goto error; } + replaces++; } } } @@ -1175,7 +984,6 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) tr = _alpm_trans_new(); if(tr == NULL) { _alpm_log(PM_LOG_ERROR, _("could not create transaction\n")); - pm_errno = PM_ERR_MEMORY; goto error; } if(_alpm_trans_init(tr, PM_TRANS_TYPE_UPGRADE, trans->flags | PM_TRANS_FLAG_NODEPS, trans->cb_event, trans->cb_conv, trans->cb_progress) == -1) { @@ -1189,6 +997,9 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) char *fpath; fname = alpm_pkg_get_filename(spkg); + if(fname == NULL) { + goto error; + } /* Loop through the cache dirs until we find a matching file */ fpath = _alpm_filecache_find(fname); @@ -1201,9 +1012,7 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) /* using alpm_list_last() is ok because addtarget() adds the new target at the * end of the tr->packages list */ spkg = alpm_list_last(tr->packages)->data; - if(sync->type == PM_SYNC_TYPE_DEPEND) { - spkg->reason = PM_PKG_REASON_DEPEND; - } + spkg->reason = sync->newreason; } if(_alpm_trans_prepare(tr, data) == -1) { _alpm_log(PM_LOG_ERROR, _("could not prepare transaction\n")); @@ -1214,15 +1023,15 @@ int _alpm_sync_commit(pmtrans_t *trans, pmdb_t *db_local, alpm_list_t **data) _alpm_log(PM_LOG_ERROR, _("could not commit transaction\n")); goto error; } - _alpm_trans_free(tr); - tr = NULL; - - return(0); + ret = 0; error: + FREELIST(files); + alpm_list_free(deltas); + deltas = NULL; _alpm_trans_free(tr); tr = NULL; - return(-1); + return(ret); } pmsyncpkg_t *_alpm_sync_find(alpm_list_t *syncpkgs, const char* pkgname) @@ -1246,14 +1055,6 @@ pmsyncpkg_t *_alpm_sync_find(alpm_list_t *syncpkgs, const char* pkgname) return(NULL); /* not found */ } -pmsynctype_t SYMEXPORT alpm_sync_get_type(const pmsyncpkg_t *sync) -{ - /* Sanity checks */ - ASSERT(sync != NULL, return(-1)); - - return sync->type; -} - pmpkg_t SYMEXPORT *alpm_sync_get_pkg(const pmsyncpkg_t *sync) { /* Sanity checks */ @@ -1262,12 +1063,12 @@ pmpkg_t SYMEXPORT *alpm_sync_get_pkg(const pmsyncpkg_t *sync) return sync->pkg; } -void SYMEXPORT *alpm_sync_get_data(const pmsyncpkg_t *sync) +alpm_list_t SYMEXPORT *alpm_sync_get_removes(const pmsyncpkg_t *sync) { /* Sanity checks */ ASSERT(sync != NULL, return(NULL)); - return sync->data; + return sync->removes; } /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/sync.h b/lib/libalpm/sync.h index a6a3e74f..b71f0ef2 100644 --- a/lib/libalpm/sync.h +++ b/lib/libalpm/sync.h @@ -25,12 +25,12 @@ /* Sync package */ struct __pmsyncpkg_t { - pmsynctype_t type; + pmpkgreason_t newreason; pmpkg_t *pkg; - void *data; + alpm_list_t *removes; }; -pmsyncpkg_t *_alpm_sync_new(int type, pmpkg_t *spkg, void *data); +pmsyncpkg_t *_alpm_sync_new(pmpkgreason_t newreason, pmpkg_t *spkg, alpm_list_t *removes); void _alpm_sync_free(pmsyncpkg_t *data); int _alpm_sync_sysupgrade(pmtrans_t *trans, diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c index ecc40a0f..eb53e952 100644 --- a/lib/libalpm/trans.c +++ b/lib/libalpm/trans.c @@ -35,7 +35,6 @@ /* libalpm */ #include "trans.h" #include "alpm_list.h" -#include "error.h" #include "package.h" #include "util.h" #include "log.h" @@ -228,7 +227,6 @@ pmtrans_t *_alpm_trans_new() CALLOC(trans, 1, sizeof(pmtrans_t), RET_ERR(PM_ERR_MEMORY, NULL)); - trans->targets = NULL; trans->packages = NULL; trans->skip_add = NULL; trans->skip_remove = NULL; @@ -250,10 +248,10 @@ void _alpm_trans_free(pmtrans_t *trans) return; } - FREELIST(trans->targets); if(trans->type == PM_TRANS_TYPE_SYNC) { alpm_list_free_inner(trans->packages, (alpm_list_fn_free)_alpm_sync_free); - } else { + } else if (trans->type == PM_TRANS_TYPE_REMOVE || + trans->type == PM_TRANS_TYPE_REMOVEUPGRADE) { alpm_list_free_inner(trans->packages, (alpm_list_fn_free)_alpm_pkg_free); } alpm_list_free(trans->packages); @@ -307,13 +305,7 @@ int _alpm_trans_addtarget(pmtrans_t *trans, char *target) ASSERT(trans != NULL, RET_ERR(PM_ERR_TRANS_NULL, -1)); ASSERT(target != NULL, RET_ERR(PM_ERR_WRONG_ARGS, -1)); - if(alpm_list_find_str(trans->targets, target)) { - return(0); - //RET_ERR(PM_ERR_TRANS_DUP_TARGET, -1); - } - switch(trans->type) { - case PM_TRANS_TYPE_ADD: case PM_TRANS_TYPE_UPGRADE: if(_alpm_add_loadtarget(trans, handle->db_local, target) == -1) { /* pm_errno is set by _alpm_add_loadtarget() */ @@ -335,8 +327,6 @@ int _alpm_trans_addtarget(pmtrans_t *trans, char *target) break; } - trans->targets = alpm_list_add(trans->targets, strdup(target)); - return(0); } @@ -357,7 +347,6 @@ int _alpm_trans_prepare(pmtrans_t *trans, alpm_list_t **data) } switch(trans->type) { - case PM_TRANS_TYPE_ADD: case PM_TRANS_TYPE_UPGRADE: if(_alpm_add_prepare(trans, handle->db_local, data) == -1) { /* pm_errno is set by _alpm_add_prepare() */ @@ -402,7 +391,6 @@ int _alpm_trans_commit(pmtrans_t *trans, alpm_list_t **data) trans->state = STATE_COMMITING; switch(trans->type) { - case PM_TRANS_TYPE_ADD: case PM_TRANS_TYPE_UPGRADE: if(_alpm_add_commit(trans, handle->db_local) == -1) { /* pm_errno is set by _alpm_add_commit() */ @@ -636,15 +624,6 @@ unsigned int SYMEXPORT alpm_trans_get_flags() return handle->trans->flags; } -alpm_list_t SYMEXPORT * alpm_trans_get_targets() -{ - /* Sanity checks */ - ASSERT(handle != NULL, return(NULL)); - ASSERT(handle->trans != NULL, return(NULL)); - - return handle->trans->targets; -} - alpm_list_t SYMEXPORT * alpm_trans_get_pkgs() { /* Sanity checks */ diff --git a/lib/libalpm/trans.h b/lib/libalpm/trans.h index 75608ce4..d74c3e90 100644 --- a/lib/libalpm/trans.h +++ b/lib/libalpm/trans.h @@ -39,7 +39,6 @@ struct __pmtrans_t { pmtranstype_t type; pmtransflag_t flags; pmtransstate_t state; - alpm_list_t *targets; /* list of (char *) */ alpm_list_t *packages; /* list of (pmpkg_t *) or (pmsyncpkg_t *) */ alpm_list_t *skip_add; /* list of (char *) */ alpm_list_t *skip_remove; /* list of (char *) */ diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index e1413a25..55bd46a8 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -43,7 +43,6 @@ /* libalpm */ #include "util.h" #include "log.h" -#include "error.h" #include "package.h" #include "alpm.h" #include "alpm_list.h" @@ -186,57 +185,65 @@ int _alpm_makepath(const char *path) /* does the same thing as 'mkdir -p' */ int _alpm_makepath_mode(const char *path, mode_t mode) { - char *orig, *str, *ptr; - char full[PATH_MAX] = ""; - mode_t oldmask; - - oldmask = umask(0000); + /* A bit of pointer hell here. Descriptions: + * orig - a copy of path so we can safely butcher it with strsep + * str - the current position in the path string (after the delimiter) + * ptr - the original position of str after calling strsep + * incr - incrementally generated path for use in stat/mkdir call + */ + char *orig, *str, *ptr, *incr; + mode_t oldmask = umask(0000); + int ret = 0; orig = strdup(path); + incr = calloc(strlen(orig) + 1, sizeof(char)); str = orig; while((ptr = strsep(&str, "/"))) { if(strlen(ptr)) { struct stat buf; - - strcat(full, "/"); - strcat(full, ptr); - if(stat(full, &buf)) { - if(mkdir(full, mode)) { - FREE(orig); - umask(oldmask); - _alpm_log(PM_LOG_ERROR, _("failed to make path '%s' : %s\n"), - path, strerror(errno)); - return(1); + /* we have another path component- append the newest component to + * existing string and create one more level of dir structure */ + strcat(incr, "/"); + strcat(incr, ptr); + if(stat(incr, &buf)) { + if(mkdir(incr, mode)) { + ret = 1; + break; } } } } - FREE(orig); + free(orig); + free(incr); umask(oldmask); - return(0); + return(ret); } +#define CPBUFSIZE 8 * 1024 + int _alpm_copyfile(const char *src, const char *dest) { FILE *in, *out; size_t len; - char buf[4097]; + char *buf; + int ret = 0; - in = fopen(src, "r"); + in = fopen(src, "rb"); if(in == NULL) { return(1); } - out = fopen(dest, "w"); + out = fopen(dest, "wb"); if(out == NULL) { fclose(in); return(1); } + CALLOC(buf, (size_t)CPBUFSIZE, (size_t)1, ret = 1; goto cleanup;); + /* do the actual file copy */ - while((len = fread(buf, 1, 4096, in))) { + while((len = fread(buf, 1, CPBUFSIZE, in))) { fwrite(buf, 1, len, out); } - fclose(in); /* chmod dest to permissions of src, as long as it is not a symlink */ struct stat statbuf; @@ -246,12 +253,14 @@ int _alpm_copyfile(const char *src, const char *dest) } } else { /* stat was unsuccessful */ - fclose(out); - return(1); + ret = 1; } +cleanup: + fclose(in); fclose(out); - return(0); + FREE(buf); + return(ret); } /* Trim whitespace and newlines from a string @@ -371,6 +380,13 @@ int _alpm_lckrm() /* Compression functions */ +/** + * @brief Unpack a specific file or all files in an archive. + * + * @param archive the archive to unpack + * @param prefix where to extract the files + * @param fn a file within the archive to unpack or NULL for all + */ int _alpm_unpack(const char *archive, const char *prefix, const char *fn) { int ret = 1; @@ -382,7 +398,7 @@ int _alpm_unpack(const char *archive, const char *prefix, const char *fn) ALPM_LOG_FUNC; if((_archive = archive_read_new()) == NULL) - RET_ERR(PM_ERR_LIBARCHIVE_ERROR, -1); + RET_ERR(PM_ERR_LIBARCHIVE, -1); archive_read_support_compression_all(_archive); archive_read_support_format_all(_archive); @@ -408,13 +424,17 @@ int _alpm_unpack(const char *archive, const char *prefix, const char *fn) archive_entry_set_mode(entry, 0755); } + /* If a specific file was requested skip entries that don't match. */ if (fn && strcmp(fn, entryname)) { + _alpm_log(PM_LOG_DEBUG, "skipping: %s\n", entryname); if (archive_read_data_skip(_archive) != ARCHIVE_OK) { ret = 1; goto cleanup; } continue; } + + /* Extract the archive entry. */ ret = 0; snprintf(expath, PATH_MAX, "%s/%s", prefix, entryname); archive_entry_set_pathname(entry, expath); @@ -535,8 +555,8 @@ int _alpm_str_cmp(const void *s1, const void *s2) return(strcmp(s1, s2)); } -/** Find a package file in an alpm cachedir. - * @param filename name of package file to find +/** Find a filename in a registered alpm cachedir. + * @param filename name of file to find * @return malloced path of file, NULL if not found */ char *_alpm_filecache_find(const char* filename) @@ -640,13 +660,7 @@ char SYMEXPORT *alpm_get_md5sum(const char *filename) ret = md5_file(filename, output); if (ret > 0) { - if (ret == 1) { - _alpm_log(PM_LOG_ERROR, _("md5: %s can't be opened\n"), filename); - } else if (ret == 2) { - _alpm_log(PM_LOG_ERROR, _("md5: %s can't be read\n"), filename); - } - - return(NULL); + RET_ERR(PM_ERR_NOT_A_FILE, NULL); } /* Convert the result to something readable */ @@ -660,4 +674,52 @@ char SYMEXPORT *alpm_get_md5sum(const char *filename) return(md5sum); } +int _alpm_test_md5sum(const char *filepath, const char *md5sum) +{ + char *md5sum2; + int ret; + + md5sum2 = alpm_get_md5sum(filepath); + + if(md5sum == NULL || md5sum2 == NULL) { + ret = -1; + } else if(strcmp(md5sum, md5sum2) != 0) { + ret = 1; + } else { + ret = 0; + } + + FREE(md5sum2); + return(ret); +} + +char *_alpm_archive_fgets(char *line, size_t size, struct archive *a) +{ + /* for now, just read one char at a time until we get to a + * '\n' char. we can optimize this later with an internal + * buffer. */ + /* leave room for zero terminator */ + char *last = line + size - 1; + char *i; + + for(i = line; i < last; i++) { + int ret = archive_read_data(a, i, 1); + /* special check for first read- if null, return null, + * this indicates EOF */ + if(i == line && (ret <= 0 || *i == '\0')) { + return(NULL); + } + /* check if read value was null or newline */ + if(ret <= 0 || *i == '\0' || *i == '\n') { + last = i + 1; + break; + } + } + + /* always null terminate the buffer */ + *last = '\0'; + + return(line); +} + /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h index e9e0af1f..6c7a05e9 100644 --- a/lib/libalpm/util.h +++ b/lib/libalpm/util.h @@ -30,6 +30,7 @@ #include <stdarg.h> #include <time.h> #include <sys/stat.h> /* struct stat */ +#include <archive.h> /* struct archive */ #ifdef ENABLE_NLS #include <libintl.h> /* here so it doesn't need to be included elsewhere */ @@ -43,12 +44,17 @@ #define MALLOC(p, s, action) do { p = calloc(1, s); if(p == NULL) { ALLOC_FAIL(s); action; } } while(0) #define CALLOC(p, l, s, action) do { p = calloc(l, s); if(p == NULL) { ALLOC_FAIL(s); action; } } while(0) -#define STRDUP(r, s, action) do { r = strdup(s); if(r == NULL) { ALLOC_FAIL(strlen(s)); action; } } while(0) +/* This strdup macro is NULL safe- copying NULL will yield NULL */ +#define STRDUP(r, s, action) do { if(s != NULL) { r = strdup(s); if(r == NULL) { ALLOC_FAIL(strlen(s)); action; } } else { r = NULL; } } while(0) -#define FREE(p) do { if(p) { free(p); p = NULL; } } while(0) +#define FREE(p) do { free(p); p = NULL; } while(0) #define ASSERT(cond, action) do { if(!(cond)) { action; } } while(0) +#define RET_ERR(err, ret) do { pm_errno = (err); \ + _alpm_log(PM_LOG_DEBUG, "returning error %d from %s : %s\n", err, __func__, alpm_strerrorlast()); \ + return(ret); } while(0) + int _alpm_makepath(const char *path); int _alpm_makepath_mode(const char *path, mode_t mode); int _alpm_copyfile(const char *src, const char *dest); @@ -64,6 +70,8 @@ int _alpm_str_cmp(const void *s1, const void *s2); char *_alpm_filecache_find(const char *filename); const char *_alpm_filecache_setup(void); int _alpm_lstat(const char *path, struct stat *buf); +int _alpm_test_md5sum(const char *filepath, const char *md5sum); +char *_alpm_archive_fgets(char *line, size_t size, struct archive *a); #ifndef HAVE_STRVERSCMP int strverscmp(const char *, const char *); @@ -2,7 +2,7 @@ # NOTE: Changing this file will not affect anything until you rerun configure. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, -# 2007 Free Software Foundation, Inc. +# 2007, 2008 Free Software Foundation, Inc. # Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 # # This program is free software; you can redistribute it and/or modify @@ -43,8 +43,8 @@ EXIT_FAILURE=1 PROGRAM=ltmain.sh PACKAGE=libtool -VERSION=1.5.24 -TIMESTAMP=" (1.1220.2.455 2007/06/24 02:13:29)" +VERSION=1.5.26 +TIMESTAMP=" (1.1220.2.492 2008/01/30 06:40:56)" # Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE). if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then @@ -113,15 +113,21 @@ esac # These must not be set unconditionally because not all systems understand # e.g. LANG=C (notably SCO). # We save the old values to restore during execute mode. -for lt_var in LANG LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +lt_env= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var + lt_env=\"$lt_var=\$$lt_var \$lt_env\" $lt_var=C export $lt_var fi" done +if test -n "$lt_env"; then + lt_env="env $lt_env" +fi + # Make sure IFS has a sensible default lt_nl=' ' @@ -485,7 +491,7 @@ do echo "\ $PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP -Copyright (C) 2007 Free Software Foundation, Inc. +Copyright (C) 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." exit $? @@ -788,6 +794,7 @@ if test -z "$show_help"; then *.for) xform=for ;; *.java) xform=java ;; *.obj) xform=obj ;; + *.sx) xform=sx ;; esac libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` @@ -956,7 +963,7 @@ EOF $run $rm "$lobj" "$output_obj" $show "$command" - if $run eval "$command"; then : + if $run eval $lt_env "$command"; then : else test -n "$output_obj" && $run $rm $removelist exit $EXIT_FAILURE @@ -1028,7 +1035,7 @@ EOF command="$command$suppress_output" $run $rm "$obj" "$output_obj" $show "$command" - if $run eval "$command"; then : + if $run eval $lt_env "$command"; then : else $run $rm $removelist exit $EXIT_FAILURE @@ -1161,6 +1168,7 @@ EOF thread_safe=no vinfo= vinfo_number=no + single_module="${wl}-single_module" func_infer_tag $base_compile @@ -1646,6 +1654,11 @@ EOF continue ;; + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + -module) module=yes continue @@ -2149,7 +2162,12 @@ EOF continue fi name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` - for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" @@ -2945,12 +2963,18 @@ EOF # we do not want to link against static libs, # but need to link against shared eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + eval deplibdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done - if test -f "$path/$depdepl" ; then + if test -f "$deplibdir/$depdepl" ; then + depdepl="$deplibdir/$depdepl" + elif test -f "$path/$depdepl" ; then depdepl="$path/$depdepl" + else + # Can't find it, oh well... + depdepl= fi # do not add paths which are already there case " $newlib_search_path " in @@ -3098,9 +3122,10 @@ EOF case $linkmode in oldlib) - if test -n "$deplibs"; then - $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 - fi + case " $deplibs" in + *\ -l* | *\ -L*) + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 ;; + esac if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 @@ -4237,9 +4262,10 @@ EOF ;; obj) - if test -n "$deplibs"; then - $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 - fi + case " $deplibs" in + *\ -l* | *\ -L*) + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 ;; + esac if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 @@ -6478,7 +6504,7 @@ relink_command=\"$relink_command\"" fi # Restore saved environment variables - for lt_var in LANG LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var diff --git a/pactest/Makefile.am b/pactest/Makefile.am index 879f23d0..85bb8017 100644 --- a/pactest/Makefile.am +++ b/pactest/Makefile.am @@ -7,8 +7,7 @@ check_SCRIPTS = \ pmrule.py \ pmtest.py \ util.py \ - $(wildcard tests/*.py) \ - tests/TESTS + $(wildcard tests/*.py) noinst_SCRIPTS = $(check_SCRIPTS) diff --git a/pactest/pmtest.py b/pactest/pmtest.py index cd532dcf..e8f6fa8d 100755 --- a/pactest/pmtest.py +++ b/pactest/pmtest.py @@ -83,7 +83,8 @@ class pmtest: "noupgrade": [], "ignorepkg": [], "ignoregroup": [], - "noextract": [] + "noextract": [], + "syncfirst": [] } # Test rules @@ -188,18 +189,22 @@ class pmtest: cmd = [""] if os.geteuid() != 0: - cmd.append("fakeroot") + fakeroot = which("fakeroot") + if not fakeroot: + print "WARNING: fakeroot not found!" + else: + cmd.append("fakeroot") - fakechroot = which("fakechroot") - if not fakechroot: - print "WARNING: fakechroot not found, scriptlet tests WILL fail!!!" - else: - cmd.append("fakechroot") + fakechroot = which("fakechroot") + if not fakechroot: + print "WARNING: fakechroot not found, scriptlet tests WILL fail!!!" + else: + cmd.append("fakechroot") if pacman["gdb"]: - cmd.append("libtool gdb --args") + cmd.append("libtool execute gdb --args") if pacman["valgrind"]: - cmd.append("valgrind --tool=memcheck --leak-check=full --show-reachable=yes") + cmd.append("valgrind -q --tool=memcheck --leak-check=full --show-reachable=yes") cmd.append("\"%s\" --config=\"%s\" --root=\"%s\" --dbpath=\"%s\" --cachedir=\"%s\"" \ % (pacman["bin"], os.path.join(self.root, PACCONF), @@ -233,11 +238,6 @@ class pmtest: vprint("\tretcode = %s" % self.retcode) os.chdir(curdir) - # Check if pacman failed because of bad permissions - if self.retcode and not pacman["nolog"] \ - and grep(os.path.join(self.root, LOGFILE), - "you cannot perform this operation unless you are root"): - print "\tERROR: pacman support for fakeroot is not disabled" # Check if the lock is still there if os.path.isfile(PM_LOCK): print "\tERROR: %s not removed" % PM_LOCK diff --git a/pactest/tests/TESTS b/pactest/tests/TESTS deleted file mode 100644 index e09a78b9..00000000 --- a/pactest/tests/TESTS +++ /dev/null @@ -1,63 +0,0 @@ -TODO: this is really outdated, needs regeneration (after we rename tests) - -add001: Install a package -add002: Install a package (already installed) -add003: Install a set of packages -add004: Install a set of the same package at different versions -add010: Install a package with a filesystem conflict -add011: Install a package with a filesystem conflict (--force) -add012: Install two packages with a conflicting file -add013: Install two packages with a conflicting file (--force) -add020: Install a package with an existing file -add021: Install a package with an existing file (new modified) -add030: Freshen a package -add031: Freshen a package (installed is newer) -add032: Freshen a package (installed is newer) -add040: Install a package with a missing dependency -add041: Install a package with a missing dependency (nodeps) -add042: Install a package with cascaded dependencies -add050: Install a package with a file in NoUpgrade -add060: Install a package with a file in NoExtract -query001: Query a package -remove010: Remove a package, with a file marked for backup -remove011: Remove a package, with a modified file marked for backup -remove020: Remove a package, with a file marked for backup (--nosave) -remove021: Remove a package, with a modified file marked for backup (--nosave) -smoke001: Install a thousand packages in a single transaction -sync001: Install a package from a sync db -sync002: Upgrade a package from a sync db -sync003: Install a package from a sync db, with a filesystem conflict -sync010: Install a package from a sync db, with its dependencies -sync040: Install two targets with a conflict -sync041: Install two conflicting targets -sync042: Install a sync package conflicting with a local one -sync043: Install a sync package conflicting with a local one -sync050: Install a virtual target (provided by a sync package) -sync100: Sysupgrade with a newer sync package -sync101: Sysupgrade with same version for local and sync packages -sync102: Sysupgrade with a newer local package -sync103: Sysupgrade with a local package not existing in sync db -sync110: Sysupgrade of a package pulling new dependencies -sync120: Sysupgrade of packages in 'IgnorePkg' -sync130: Sysupgrade with a sync package replacing a local one -sync131: Sysupgrade with a sync package replacing a set of local ones -sync132: Sysupgrade with a replacement for a local package out of date -sync133: Sysupgrade with a sync package replacing a local one in 'IgnorePkg' -sync134: Sysupgrade with a set of sync packages replacing a set local one -sync135: Sysupgrade with a set of sync packages replacing a set of local ones -sync897: System upgrade -sync898: System upgrade -sync899: System upgrade -sync990: Sync a package pulling a dependency conflicting with a target -sync992: Sync a package pulling a conflicting dependency -sync999: System upgrade -upgrade001: Upgrade a package (newer version) -upgrade002: Upgrade a package (same version) -upgrade003: Upgrade a package (lesser version) -upgrade004: Upgrade a package (not installed) -upgrade010: Upgrade a package, with a file in NoUpgrade -upgrade020: Upgrade a package, with a file in 'backup' (new modified) -upgrade021: Upgrade a package, with a file in 'backup' (local modified, new unchanged) -upgrade022: Upgrade a package, with a file in 'backup' (local and new modified) -upgrade030: Upgrade packages with various reasons -upgrade040: file relocation 1 diff --git a/pactest/tests/add001.py b/pactest/tests/add001.py deleted file mode 100644 index 3dde4061..00000000 --- a/pactest/tests/add001.py +++ /dev/null @@ -1,13 +0,0 @@ -self.description = "Install a simple package with two files" - -p = pmpkg("dummy") -p.files = ["bin/dummy", - "usr/man/man1/dummy.1"] -self.addpkg(p) - -self.args = "-A %s" % p.filename() - -self.addrule("PACMAN_RETCODE=0") -self.addrule("PKG_EXIST=dummy") -for f in p.files: - self.addrule("FILE_EXIST=%s" % f) diff --git a/pactest/tests/add002.py b/pactest/tests/add002.py deleted file mode 100644 index f6bc91a2..00000000 --- a/pactest/tests/add002.py +++ /dev/null @@ -1,18 +0,0 @@ -self.description = "Install an already-installed package" - -lp = pmpkg("dummy") -lp.files = ["bin/dummy", - "usr/man/man1/dummy.1"] -self.addpkg2db("local", lp) - -p = pmpkg("dummy") -p.files = ["bin/dummy", - "usr/man/man1/dummy.1"] -self.addpkg(p) - -self.args = "-A %s" % p.filename() - -self.addrule("PACMAN_RETCODE=1") -self.addrule("!PKG_MODIFIED=dummy") -for f in lp.files: - self.addrule("!FILE_MODIFIED=%s" % f) diff --git a/pactest/tests/add004.py b/pactest/tests/add004.py deleted file mode 100644 index d0188563..00000000 --- a/pactest/tests/add004.py +++ /dev/null @@ -1,18 +0,0 @@ -self.description = "Install three of the same package at different versions" - -p1 = pmpkg("dummy", "1.0-2") -p1.files = ["bin/dummy"] -p2 = pmpkg("dummy", "2.0-1") -p2.files = ["bin/dummy"] -p3 = pmpkg("dummy") -p3.files = ["bin/dummy"] - -for p in p1, p2, p3: - self.addpkg(p) - -self.args = "-A %s" % " ".join([p.filename() for p in p1, p2, p3]) - -self.addrule("PACMAN_RETCODE=0") -self.addrule("PKG_VERSION=dummy|2.0-1") -for f in p2.files: - self.addrule("FILE_EXIST=%s" % f) diff --git a/pactest/tests/add010.py b/pactest/tests/add010.py deleted file mode 100644 index a7874746..00000000 --- a/pactest/tests/add010.py +++ /dev/null @@ -1,15 +0,0 @@ -self.description = "Install a package with a filesystem conflict" - -p = pmpkg("dummy") -p.files = ["bin/dummy", - "usr/man/man1/dummy.1"] -self.addpkg(p) - -self.filesystem = ["bin/dummy"] - -self.args = "-A %s" % p.filename() - -self.addrule("PACMAN_RETCODE=1") -self.addrule("!PKG_EXIST=dummy") -self.addrule("!FILE_MODIFIED=bin/dummy") -self.addrule("!FILE_EXIST=usr/man/man1/dummy.1") diff --git a/pactest/tests/add050.py b/pactest/tests/add050.py deleted file mode 100644 index b48459ab..00000000 --- a/pactest/tests/add050.py +++ /dev/null @@ -1,17 +0,0 @@ -self.description = "Install a package with a file in NoUpgrade" - -p = pmpkg("dummy") -p.files = ["etc/dummy.conf"] -p.backup = ["etc/dummy.conf"] -self.addpkg(p) - -self.filesystem = ["etc/dummy.conf"] - -self.option["noupgrade"] = ["etc/dummy.conf"] - -self.args = "-Af %s" % p.filename() - -self.addrule("PACMAN_RETCODE=0") -self.addrule("PKG_EXIST=dummy") -self.addrule("!FILE_MODIFIED=etc/dummy.conf") -self.addrule("FILE_PACNEW=etc/dummy.conf") diff --git a/pactest/tests/depconflict110.py b/pactest/tests/depconflict110.py index 2e326f52..fd56fa89 100644 --- a/pactest/tests/depconflict110.py +++ b/pactest/tests/depconflict110.py @@ -7,7 +7,7 @@ self.addpkg(p); lp = pmpkg("pkg2", "1.0-1") self.addpkg2db("local", lp) -self.args = "-A %s" % p.filename() +self.args = "-U %s" % p.filename() self.addrule("PACMAN_RETCODE=1") self.addrule("!PKG_EXIST=pkg1") self.addrule("PKG_EXIST=pkg2") diff --git a/pactest/tests/depconflict111.py b/pactest/tests/depconflict111.py index 6f95733b..0d11dd92 100644 --- a/pactest/tests/depconflict111.py +++ b/pactest/tests/depconflict111.py @@ -7,7 +7,7 @@ self.addpkg(p); lp = pmpkg("pkg2", "1.0-1") self.addpkg2db("local", lp) -self.args = "-A %s" % p.filename() +self.args = "-U %s" % p.filename() self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_EXIST=pkg1") self.addrule("PKG_EXIST=pkg2") diff --git a/pactest/tests/deptest001.py b/pactest/tests/deptest001.py index db0b7684..18569bea 100644 --- a/pactest/tests/deptest001.py +++ b/pactest/tests/deptest001.py @@ -1,20 +1,16 @@ self.description = "test deptest (-T) functionality" -sp1 = pmpkg("pkg1") -sp1.depends = ["dep"] -self.addpkg2db("sync", sp1) +lp1 = pmpkg("pkg1") +self.addpkg2db("local", lp1) -sp1dep = pmpkg("dep") -self.addpkg2db("sync", sp1dep) +lp3 = pmpkg("pkg3", "2.0-1") +lp3.provides = ("prov=3.0") +self.addpkg2db("local", lp3) -sp2 = pmpkg("pkg2") -self.addpkg2db("sync", sp2) - -lp2 = pmpkg("pkg2") -self.addpkg2db("local", lp2) - -self.args = "-T pkg1 pkg2" +self.args = "-T pkg1 pkg2 pkg3\>2.1 prov\>\=3.0" self.addrule("PACMAN_RETCODE=127") -self.addrule("PACMAN_OUTPUT=pkg1") -self.addrule("!PACMAN_OUTPUT=pkg2") +self.addrule("!PACMAN_OUTPUT=pkg1") +self.addrule("PACMAN_OUTPUT=pkg2") +self.addrule("PACMAN_OUTPUT=pkg3") +self.addrule("!PACMAN_OUTPUT=prov") diff --git a/pactest/tests/fileconflict001.py b/pactest/tests/fileconflict001.py index 8aca9a0a..4c2069ee 100644 --- a/pactest/tests/fileconflict001.py +++ b/pactest/tests/fileconflict001.py @@ -13,7 +13,7 @@ p2 = pmpkg("pkg2") p2.files = ["dir/symdir/file"] self.addpkg(p2) -self.args = "-A %s" % " ".join([p.filename() for p in p1, p2]) +self.args = "-U %s" % " ".join([p.filename() for p in p1, p2]) self.addrule("PACMAN_RETCODE=1") self.addrule("!PKG_EXIST=pkg1") diff --git a/pactest/tests/fileconflict002.py b/pactest/tests/fileconflict002.py index da04e332..c54f6daf 100644 --- a/pactest/tests/fileconflict002.py +++ b/pactest/tests/fileconflict002.py @@ -9,7 +9,7 @@ p2 = pmpkg("pkg2") p2.files = ["dir/symdir/file"] self.addpkg(p2) -self.args = "-A %s" % " ".join([p.filename() for p in p1, p2]) +self.args = "-U %s" % " ".join([p.filename() for p in p1, p2]) self.addrule("PACMAN_RETCODE=1") self.addrule("!PKG_EXIST=pkg1") diff --git a/pactest/tests/ldconfig001.py b/pactest/tests/ldconfig001.py index aced413b..9ac2ff35 100644 --- a/pactest/tests/ldconfig001.py +++ b/pactest/tests/ldconfig001.py @@ -6,7 +6,7 @@ p = pmpkg("dummy") self.addpkg(p) # --debug is necessary to check PACMAN_OUTPUT -self.args = "--debug -A %s" % p.filename() +self.args = "--debug -U %s" % p.filename() self.addrule("PACMAN_RETCODE=0") self.addrule("PACMAN_OUTPUT=ldconfig") diff --git a/pactest/tests/mode001.py b/pactest/tests/mode001.py index ff245a2c..4ec11e10 100644 --- a/pactest/tests/mode001.py +++ b/pactest/tests/mode001.py @@ -1,7 +1,7 @@ self.description = "Check the mode of default files in a package" p = pmpkg("pkg1") -p.files = ["bin/foo" +p.files = ["bin/foo", "bin/bar"] self.addpkg(p) diff --git a/pactest/tests/mode002.py b/pactest/tests/mode002.py new file mode 100644 index 00000000..cc4a8fe8 --- /dev/null +++ b/pactest/tests/mode002.py @@ -0,0 +1,12 @@ +self.description = "Check execute mode on files in a package" + +p = pmpkg("pkg1") +p.files = ["bin/foo|755", + "bin/bar|755"] +self.addpkg(p) + +self.args = "-U %s" % p.filename() + +self.addrule("PACMAN_RETCODE=0") +self.addrule("FILE_MODE=bin/foo|755") +self.addrule("FILE_MODE=bin/bar|755") diff --git a/pactest/tests/mode003.py b/pactest/tests/mode003.py new file mode 100644 index 00000000..1193a5cf --- /dev/null +++ b/pactest/tests/mode003.py @@ -0,0 +1,20 @@ +self.description = "Backup file permissions test (same as orig)" + +lp = pmpkg("filesystem") +lp.files = ["etc/profile|666"] +lp.backup = ["etc/profile*"] +self.addpkg2db("local", lp) + +p = pmpkg("filesystem", "1.0-2") +p.files = ["etc/profile|666**"] +p.backup = ["etc/profile"] +self.addpkg(p) + +self.args = "-U %s" % p.filename() + +self.addrule("PACMAN_RETCODE=0") +self.addrule("!FILE_PACSAVE=etc/profile") +self.addrule("FILE_PACNEW=etc/profile") +self.addrule("FILE_EXIST=etc/profile") +self.addrule("FILE_MODE=etc/profile|666") +self.addrule("FILE_MODE=etc/profile.pacnew|666") diff --git a/pactest/tests/query003.py b/pactest/tests/query003.py index ea113081..41b8a45b 100644 --- a/pactest/tests/query003.py +++ b/pactest/tests/query003.py @@ -2,6 +2,7 @@ self.description = "Query search for a package" p = pmpkg("foobar") p.files = ["bin/foobar"] +p.groups = ["group1", "group2"] self.addpkg2db("local", p) self.args = "-Qs %s" % p.name diff --git a/pactest/tests/reason001.py b/pactest/tests/reason001.py new file mode 100644 index 00000000..40433f5e --- /dev/null +++ b/pactest/tests/reason001.py @@ -0,0 +1,16 @@ +self.description = "Copy reason (to-be-replaced -> replacement)" + +sp = pmpkg("libfoo-ng") +sp.replaces = [ "libfoo" ] +self.addpkg2db("sync", sp) + +lp = pmpkg("libfoo") +lp.reason = 1 +self.addpkg2db("local", lp) + +self.args = "-Su" + +self.addrule("PACMAN_RETCODE=0") +self.addrule("!PKG_EXIST=libfoo") +self.addrule("PKG_EXIST=libfoo-ng") +self.addrule("PKG_REASON=libfoo-ng|1") diff --git a/pactest/tests/remove001.py b/pactest/tests/remove001.py index 809bfdb7..d20dd079 100644 --- a/pactest/tests/remove001.py +++ b/pactest/tests/remove001.py @@ -1,4 +1,3 @@ -# If someone else can come up with a better name, please do so self.description = "Remove a package listed 5 times" p = pmpkg("foo") @@ -6,5 +5,5 @@ self.addpkg2db("local", p) self.args = "-R " + "foo "*5 -self.addrule("PACMAN_RETCODE=0") -self.addrule("!PKG_EXISTS=foo") +self.addrule("PACMAN_RETCODE=1") +self.addrule("PKG_EXISTS=foo") diff --git a/pactest/tests/remove030.py b/pactest/tests/remove030.py index cc23f144..9e2b9da5 100644 --- a/pactest/tests/remove030.py +++ b/pactest/tests/remove030.py @@ -3,7 +3,7 @@ self.description = "Remove a package in HoldPkg" p1 = pmpkg("dummy") self.addpkg2db("local", p1) -self.option["holdpkg"] = ["dummy"] +self.option["HoldPkg"] = ["dummy"] self.args = "-R %s" % p1.name diff --git a/pactest/tests/remove049.py b/pactest/tests/remove049.py new file mode 100644 index 00000000..724f8da2 --- /dev/null +++ b/pactest/tests/remove049.py @@ -0,0 +1,19 @@ +self.description = "-Ru test" + +lp1 = pmpkg("pkg1") +lp1.requiredby = [ "pkg3" ] +self.addpkg2db("local", lp1) + +lp2 = pmpkg("pkg2") +self.addpkg2db("local", lp2) + +lp3 = pmpkg("pkg3") +lp3.depends = [ "pkg1" ] +self.addpkg2db("local", lp3) + +self.args = "-Ru pkg1 pkg2" + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_EXIST=pkg1") +self.addrule("!PKG_EXIST=pkg2") +self.addrule("PKG_EXIST=pkg3")
\ No newline at end of file diff --git a/pactest/tests/remove050.py b/pactest/tests/remove050.py new file mode 100644 index 00000000..44b0d18c --- /dev/null +++ b/pactest/tests/remove050.py @@ -0,0 +1,20 @@ +self.description = "-Rs test (exclude explicit)" + +lp1 = pmpkg("pkg1") +lp1.depends = ["pkg2" , "pkg3"] +self.addpkg2db("local", lp1) + +lp2 = pmpkg("pkg2") +lp2.reason = 1 +self.addpkg2db("local", lp2) + +lp3 = pmpkg("pkg3") +lp3.reason = 0 +self.addpkg2db("local", lp3) + +self.args = "-Rs %s" % lp1.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("!PKG_EXIST=pkg1") +self.addrule("!PKG_EXIST=pkg2") +self.addrule("PKG_EXIST=pkg3") diff --git a/pactest/tests/remove051.py b/pactest/tests/remove051.py new file mode 100644 index 00000000..bba87bba --- /dev/null +++ b/pactest/tests/remove051.py @@ -0,0 +1,20 @@ +self.description = "-Rss test (include explicit)" + +lp1 = pmpkg("pkg1") +lp1.depends = ["pkg2" , "pkg3"] +self.addpkg2db("local", lp1) + +lp2 = pmpkg("pkg2") +lp2.reason = 1 +self.addpkg2db("local", lp2) + +lp3 = pmpkg("pkg3") +lp3.reason = 0 +self.addpkg2db("local", lp3) + +self.args = "-Rss %s" % lp1.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("!PKG_EXIST=pkg1") +self.addrule("!PKG_EXIST=pkg2") +self.addrule("!PKG_EXIST=pkg3") diff --git a/pactest/tests/remove052.py b/pactest/tests/remove052.py new file mode 100644 index 00000000..df1e0db1 --- /dev/null +++ b/pactest/tests/remove052.py @@ -0,0 +1,21 @@ +self.description = "-Rs test (dependency chain)" + +lp1 = pmpkg("pkg1") +lp1.depends = ["pkg2"] +self.addpkg2db("local", lp1) + +lp2 = pmpkg("pkg2") +lp2.depends = ["pkg3"] +lp2.reason = 1 +self.addpkg2db("local", lp2) + +lp3 = pmpkg("pkg3") +lp3.reason = 1 +self.addpkg2db("local", lp3) + +self.args = "-Rs %s" % " ".join([p.name for p in lp1, lp3]) + +self.addrule("PACMAN_RETCODE=0") +self.addrule("!PKG_EXIST=pkg1") +self.addrule("!PKG_EXIST=pkg2") +self.addrule("!PKG_EXIST=pkg3") diff --git a/pactest/tests/smoke001.py b/pactest/tests/smoke001.py index 71a08d3f..c6636391 100644 --- a/pactest/tests/smoke001.py +++ b/pactest/tests/smoke001.py @@ -12,7 +12,7 @@ for i in range(1000): _list = [] [_list.append(p.filename()) for p in self.localpkgs] -self.args = "-A %s" % " ".join(_list) +self.args = "-U %s" % " ".join(_list) self.addrule("PACMAN_RETCODE=0") #for i in range(1000): diff --git a/pactest/tests/sync021.py b/pactest/tests/sync021.py index a4073eed..4c664d8e 100644 --- a/pactest/tests/sync021.py +++ b/pactest/tests/sync021.py @@ -12,7 +12,7 @@ sp3.groups = ["grp"] for p in sp1, sp2, sp3: self.addpkg2db("sync", p); -self.option["ignorepkg"] = ["pkg2"] +self.option["IgnorePkg"] = ["pkg2"] self.args = "-S grp" diff --git a/pactest/tests/sync031.py b/pactest/tests/sync031.py new file mode 100644 index 00000000..4aa2ee39 --- /dev/null +++ b/pactest/tests/sync031.py @@ -0,0 +1,19 @@ +self.description = "Sync packages explicitly" + +lp1 = pmpkg("pkg1") +lp1.reason = 1 +self.addpkg2db("local", lp1) + +p1 = pmpkg("pkg1", "1.0-2") +p2 = pmpkg("pkg2", "1.0-2") + +for p in p1, p2: + self.addpkg2db("sync", p) + +self.args = "-S --asexplicit %s" % " ".join([p.name for p in p1, p2]) + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_VERSION=pkg1|1.0-2") +self.addrule("PKG_VERSION=pkg2|1.0-2") +self.addrule("PKG_REASON=pkg1|0") +self.addrule("PKG_REASON=pkg2|0") diff --git a/pactest/tests/sync1001.py b/pactest/tests/sync1001.py deleted file mode 100644 index 6c4aabcf..00000000 --- a/pactest/tests/sync1001.py +++ /dev/null @@ -1,18 +0,0 @@ -self.description = "Test -Se (ensure specified package is not installed)" - -sp1 = pmpkg("dummy") -sp1.depends = [ "dep1", "dep2" ] -self.addpkg2db("sync", sp1) - -sp2 = pmpkg("dep1") -self.addpkg2db("sync", sp2) - -sp3 = pmpkg("dep2") -self.addpkg2db("sync", sp3) - -self.args = "-Se dummy" - -self.addrule("PACMAN_RETCODE=0") -self.addrule("PKG_EXIST=dep1") -self.addrule("PKG_EXIST=dep2") -self.addrule("!PKG_EXIST=dummy") diff --git a/pactest/tests/sync1002.py b/pactest/tests/sync1002.py deleted file mode 100644 index c158838b..00000000 --- a/pactest/tests/sync1002.py +++ /dev/null @@ -1,19 +0,0 @@ -self.description = "Test -Se (resolve the dependencies' dependencies )" - -sp1 = pmpkg("pkg1") -sp1.depends = [ "pkg2" ] -self.addpkg2db("sync", sp1) - -sp2 = pmpkg("pkg2") -sp2.depends = [ "pkg3" ] -self.addpkg2db("sync", sp2) - -sp3 = pmpkg("pkg3") -self.addpkg2db("sync", sp3) - -self.args = "-Se pkg1 pkg3" - -self.addrule("PACMAN_RETCODE=0") -self.addrule("PKG_EXIST=pkg2") -self.addrule("PKG_EXIST=pkg3") -self.addrule("!PKG_EXIST=pkg1") diff --git a/pactest/tests/sync1006.py b/pactest/tests/sync1006.py deleted file mode 100644 index c331f42e..00000000 --- a/pactest/tests/sync1006.py +++ /dev/null @@ -1,14 +0,0 @@ -self.description = "Conflicting package names in sync repos (diff versions)" - -sp1 = pmpkg("pkg", "1.0-1") -sp1.provides = [ "provision1" ] -self.addpkg2db("sync1", sp1) - -sp2 = pmpkg("pkg", "2.0-1") -sp2.provides = [ "provision2" ] -self.addpkg2db("sync2", sp2) - -self.args = "-S provision1 provision2" - -self.addrule("PACMAN_RETCODE=1") -self.addrule("!PKG_EXIST=pkg") diff --git a/pactest/tests/sync1005.py b/pactest/tests/sync1008.py index 4fa82478..a6064597 100644 --- a/pactest/tests/sync1005.py +++ b/pactest/tests/sync1008.py @@ -1,14 +1,19 @@ self.description = "Conflicting package names in sync repos" -sp1 = pmpkg("pkg") +sp1 = pmpkg("cpkg", "1.0-1") sp1.provides = [ "provision1" ] self.addpkg2db("sync1", sp1) -sp2 = pmpkg("pkg") +sp2 = pmpkg("cpkg", "2.0-1") sp2.provides = [ "provision2" ] self.addpkg2db("sync2", sp2) -self.args = "-S provision1 provision2" +sp3 = pmpkg("pkg") +sp3.depends = [ "provision1" , "provision2" ] +self.addpkg2db("sync1", sp3) + +self.args = "-S pkg" self.addrule("PACMAN_RETCODE=1") self.addrule("!PKG_EXIST=pkg") +self.addrule("!PKG_EXIST=cpkg") diff --git a/pactest/tests/sync1101.py b/pactest/tests/sync1101.py index ba2ad44f..e3ed0f0f 100644 --- a/pactest/tests/sync1101.py +++ b/pactest/tests/sync1101.py @@ -1,6 +1,7 @@ self.description = "Search for package from a sync db" sp = pmpkg("dummy") +sp.groups = ["group1", "group2"] sp.files = ["bin/dummy", "usr/man/man1/dummy.1"] self.addpkg2db("sync", sp) diff --git a/pactest/tests/sync120.py b/pactest/tests/sync120.py index b8fc6747..994e440e 100644 --- a/pactest/tests/sync120.py +++ b/pactest/tests/sync120.py @@ -12,7 +12,7 @@ lp2 = pmpkg("pkg2") for p in lp1, lp2: self.addpkg2db("local", p) -self.option["ignorepkg"] = ["pkg2"] +self.option["IgnorePkg"] = ["pkg2"] self.args = "-Su" diff --git a/pactest/tests/sync133.py b/pactest/tests/sync133.py index b852a7fc..cea603b8 100644 --- a/pactest/tests/sync133.py +++ b/pactest/tests/sync133.py @@ -9,7 +9,7 @@ lp = pmpkg("pkg1") self.addpkg2db("local", lp) -self.option["ignorepkg"] = ["pkg1"] +self.option["IgnorePkg"] = ["pkg1"] self.args = "-Su" diff --git a/pactest/tests/sync138.py b/pactest/tests/sync138.py index 410c7f07..e67c4f46 100644 --- a/pactest/tests/sync138.py +++ b/pactest/tests/sync138.py @@ -13,7 +13,7 @@ lp2 = pmpkg("pkg2") for p in lp1, lp2: self.addpkg2db("local", p) -self.option["ignoregroup"] = ["grp"] +self.option["IgnoreGroup"] = ["grp"] self.args = "-Su" diff --git a/pactest/tests/sync301.py b/pactest/tests/sync301.py index e8526b93..96402fc3 100644 --- a/pactest/tests/sync301.py +++ b/pactest/tests/sync301.py @@ -16,10 +16,12 @@ self.addpkg2db("local", lp) lp1 = pmpkg("pkg1", "1.0-1") self.addpkg2db("local", lp1) +self.option["SyncFirst"] = ["pacman"] + self.args = "-Su" self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_EXIST=pacman") self.addrule("PKG_VERSION=pacman|1.0-2") +self.addrule("PKG_VERSION=pkg1|1.0-1") self.addrule("PKG_EXIST=dep") -self.addrule("PKG_REQUIREDBY=dep|pacman") diff --git a/pactest/tests/sync500.py b/pactest/tests/sync500.py new file mode 100644 index 00000000..ccfffa7c --- /dev/null +++ b/pactest/tests/sync500.py @@ -0,0 +1,15 @@ +self.description = "Install a package from a sync db with NoExtract" + +sp = pmpkg("dummy") +sp.files = ["bin/dummy", + "usr/man/man1/dummy.1"] +self.addpkg2db("sync", sp) + +self.option["NoExtract"] = ["usr/man/man1/dummy.1"] + +self.args = "-S %s" % sp.name + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_EXIST=dummy") +self.addrule("FILE_EXIST=bin/dummy") +self.addrule("!FILE_EXIST=usr/man/man1/dummy.1") diff --git a/pactest/tests/sync501.py b/pactest/tests/sync501.py new file mode 100644 index 00000000..eb826e21 --- /dev/null +++ b/pactest/tests/sync501.py @@ -0,0 +1,18 @@ +self.description = "Upgrade a package, with a file in NoUpgrade" + +sp = pmpkg("dummy", "1.0-2") +sp.files = ["etc/dummy.conf"] +self.addpkg2db("sync", sp) + +lp = pmpkg("dummy") +lp.files = ["etc/dummy.conf"] +self.addpkg2db("local", lp) + +self.option["NoUpgrade"] = ["etc/dummy.conf"] + +self.args = "-S %s" % sp.name + +self.addrule("PKG_VERSION=dummy|1.0-2") +self.addrule("!FILE_MODIFIED=etc/dummy.conf") +self.addrule("FILE_PACNEW=etc/dummy.conf") +self.addrule("!FILE_PACSAVE=etc/dummy.conf") diff --git a/pactest/tests/sync893.py b/pactest/tests/sync893.py index 9420b74c..1c8494a3 100644 --- a/pactest/tests/sync893.py +++ b/pactest/tests/sync893.py @@ -15,6 +15,6 @@ self.addpkg2db("local", lp2) self.args = "-S %s" % " ".join([p.name for p in sp1, sp2]) -self.addrule("PACMAN_RETCODE=0") +self.addrule("PACMAN_RETCODE=1") self.addrule("PKG_EXIST=pkg1") -self.addrule("!PKG_EXIST=pkg2") +self.addrule("PKG_EXIST=pkg2") diff --git a/pactest/tests/sync897.py b/pactest/tests/sync897.py index 3cf43929..f7bd3d71 100644 --- a/pactest/tests/sync897.py +++ b/pactest/tests/sync897.py @@ -18,7 +18,7 @@ self.addpkg2db("local", lp3) self.args = "-Su" -self.addrule("PACMAN_RETCODE=0") +self.addrule("PACMAN_RETCODE=1") self.addrule("PKG_EXIST=pkg1") -self.addrule("!PKG_EXIST=pkg2") -self.addrule("!PKG_EXIST=pkg3") +self.addrule("PKG_EXIST=pkg2") +self.addrule("PKG_EXIST=pkg3") diff --git a/pactest/tests/add003.py b/pactest/tests/upgrade005.py index 4f8ae600..0f8c13ef 100644 --- a/pactest/tests/add003.py +++ b/pactest/tests/upgrade005.py @@ -14,7 +14,7 @@ p3.files = ["bin/pkg3", "usr/man/man1/pkg3.1"] for p in p1, p2, p3: self.addpkg(p) -self.args = "-A %s" % " ".join([p.filename() for p in p1, p2, p3]) +self.args = "-U %s" % " ".join([p.filename() for p in p1, p2, p3]) self.addrule("PACMAN_RETCODE=0") for p in p1, p2, p3: diff --git a/pactest/tests/upgrade010.py b/pactest/tests/upgrade010.py index 633ef7e4..3d8b21e1 100644 --- a/pactest/tests/upgrade010.py +++ b/pactest/tests/upgrade010.py @@ -8,7 +8,7 @@ p = pmpkg("dummy", "1.0-2") p.files = ["etc/dummy.conf"] self.addpkg(p) -self.option["noupgrade"] = ["etc/dummy.conf"] +self.option["NoUpgrade"] = ["etc/dummy.conf"] self.args = "-U %s" % p.filename() diff --git a/pactest/tests/add011.py b/pactest/tests/upgrade012.py index 5d2ae43f..dba8dc18 100644 --- a/pactest/tests/add011.py +++ b/pactest/tests/upgrade012.py @@ -6,7 +6,7 @@ self.addpkg(p) self.filesystem = ["bin/dummy"] -self.args = "-Af %s" % p.filename() +self.args = "-Uf %s" % p.filename() self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_EXIST=dummy") diff --git a/pactest/tests/add012.py b/pactest/tests/upgrade013.py index 291d1fba..5a327599 100644 --- a/pactest/tests/add012.py +++ b/pactest/tests/upgrade013.py @@ -13,7 +13,7 @@ p2.files = ["bin/foobar", for p in p1, p2: self.addpkg(p) -self.args = "-A %s" % " ".join([p.filename() for p in p1, p2]) +self.args = "-U %s" % " ".join([p.filename() for p in p1, p2]) self.addrule("PACMAN_RETCODE=1") self.addrule("!PKG_EXIST=dummy") diff --git a/pactest/tests/add013.py b/pactest/tests/upgrade014.py index 547ce001..1632dd36 100644 --- a/pactest/tests/add013.py +++ b/pactest/tests/upgrade014.py @@ -13,7 +13,7 @@ p2.files = ["bin/foobar", for p in p1, p2: self.addpkg(p) -self.args = "-Af %s" % " ".join([p.filename() for p in p1, p2]) +self.args = "-Uf %s" % " ".join([p.filename() for p in p1, p2]) self.addrule("PACMAN_RETCODE=0") for p in p1, p2: diff --git a/pactest/tests/add020.py b/pactest/tests/upgrade015.py index 8a2f4a71..22f7c36b 100644 --- a/pactest/tests/add020.py +++ b/pactest/tests/upgrade015.py @@ -6,7 +6,7 @@ self.addpkg(p) self.filesystem = ["etc/dummy.conf"] -self.args = "-Af %s" % p.filename() +self.args = "-Uf %s" % p.filename() self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_EXIST=dummy") diff --git a/pactest/tests/add021.py b/pactest/tests/upgrade016.py index a6dda963..dd31c9ab 100644 --- a/pactest/tests/add021.py +++ b/pactest/tests/upgrade016.py @@ -7,7 +7,7 @@ self.addpkg(p) self.filesystem = ["etc/dummy.conf"] -self.args = "-Af %s" % p.filename() +self.args = "-Uf %s" % p.filename() self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_EXIST=dummy") diff --git a/pactest/tests/upgrade032.py b/pactest/tests/upgrade032.py new file mode 100644 index 00000000..85e048e0 --- /dev/null +++ b/pactest/tests/upgrade032.py @@ -0,0 +1,19 @@ +self.description = "Install packages explicitly" + +lp1 = pmpkg("pkg1") +lp1.reason = 1 +self.addpkg2db("local", lp1) + +p1 = pmpkg("pkg1", "1.0-2") +p2 = pmpkg("pkg2", "1.0-2") + +for p in p1, p2: + self.addpkg(p) + +self.args = "-U --asexplicit %s" % " ".join([p.filename() for p in p1, p2]) + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_VERSION=pkg1|1.0-2") +self.addrule("PKG_VERSION=pkg2|1.0-2") +self.addrule("PKG_REASON=pkg1|0") +self.addrule("PKG_REASON=pkg2|0") diff --git a/pactest/tests/add060.py b/pactest/tests/upgrade070.py index 4c5f17da..01f0ba48 100644 --- a/pactest/tests/add060.py +++ b/pactest/tests/upgrade070.py @@ -5,9 +5,9 @@ p.files = ["bin/dummy", "usr/man/man1/dummy.1"] self.addpkg(p) -self.option["noextract"] = ["usr/man/man1/dummy.1"] +self.option["NoExtract"] = ["usr/man/man1/dummy.1"] -self.args = "-A %s" % p.filename() +self.args = "-U %s" % p.filename() self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_EXIST=dummy") diff --git a/pactest/tests/add040.py b/pactest/tests/upgrade071.py index 6d6da602..1f21c558 100644 --- a/pactest/tests/add040.py +++ b/pactest/tests/upgrade071.py @@ -6,7 +6,7 @@ p.files = ["bin/dummy", p.depends = ["dep1"] self.addpkg(p) -self.args = "-A %s" % p.filename() +self.args = "-U %s" % p.filename() self.addrule("PACMAN_RETCODE=1") self.addrule("!PKG_EXIST=dummy") diff --git a/pactest/tests/add041.py b/pactest/tests/upgrade072.py index af3ffe46..f88e150c 100644 --- a/pactest/tests/add041.py +++ b/pactest/tests/upgrade072.py @@ -6,7 +6,7 @@ p.files = ["bin/dummy", p.depends = ["dep1"] self.addpkg(p) -self.args = "-Ad %s" % p.filename() +self.args = "-Ud %s" % p.filename() self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_EXIST=dummy") diff --git a/pactest/tests/add042.py b/pactest/tests/upgrade073.py index 48104b0c..3486c417 100644 --- a/pactest/tests/add042.py +++ b/pactest/tests/upgrade073.py @@ -15,7 +15,7 @@ p3.files = ["bin/dep2"] for p in p1, p2, p3: self.addpkg(p) -self.args = "-A %s" % " ".join([p.filename() for p in p1, p2, p3]) +self.args = "-U %s" % " ".join([p.filename() for p in p1, p2, p3]) self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_VERSION=dummy|1.0-2") diff --git a/pactest/tests/add046.py b/pactest/tests/upgrade074.py index 5f967cbe..ca052855 100644 --- a/pactest/tests/add046.py +++ b/pactest/tests/upgrade074.py @@ -7,7 +7,7 @@ self.addpkg(p) lp = pmpkg("pkg2", "1.9b-3") self.addpkg2db("local", lp) -self.args = "-A %s" % p.filename() +self.args = "-U %s" % p.filename() self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_EXIST=pkg1") diff --git a/pactest/tests/add047.py b/pactest/tests/upgrade075.py index 153364a5..8d2f3fc4 100644 --- a/pactest/tests/add047.py +++ b/pactest/tests/upgrade075.py @@ -7,7 +7,7 @@ self.addpkg(p) lp = pmpkg("pkg2", "2.0-3") self.addpkg2db("local", lp) -self.args = "-A %s" % p.filename() +self.args = "-U %s" % p.filename() self.addrule("PACMAN_RETCODE=1") self.addrule("!PKG_EXIST=pkg1") diff --git a/pactest/tests/xfercommand001.py b/pactest/tests/xfercommand001.py index a9c41d8c..a645cf7f 100644 --- a/pactest/tests/xfercommand001.py +++ b/pactest/tests/xfercommand001.py @@ -3,7 +3,7 @@ self.description = "Quick check for using XferCommand" # this setting forces us to download packages self.cachepkgs = False #wget doesn't support file:// urls. curl does -self.option['xfercommand'] = ['/usr/bin/curl %u > %o'] +self.option['XferCommand'] = ['/usr/bin/curl %u > %o'] numpkgs = 10 pkgnames = [] diff --git a/pactest/util.py b/pactest/util.py index 2a6ff4e7..c6d5a594 100755 --- a/pactest/util.py +++ b/pactest/util.py @@ -58,35 +58,35 @@ def vprint(msg): def getfilename(name): """ """ - filename = "" - link = "" - if name.find(" -> ") != -1: - filename, link = name.split(" -> ") - elif name[-1] == "*": - filename = name.rstrip("*") - else: - filename = name + filename = name + extra = "" + if filename[-1] == "*": + filename = filename.rstrip("*") + if filename.find(" -> ") != -1: + filename, extra = filename.split(" -> ") + elif filename.find("|") != -1: + filename, extra = filename.split("|") return filename def mkfile(name, data = ""): """ """ - - isaltered = 0 isdir = 0 islink = 0 + setperms = 0 + filename = name link = "" - filename = "" + perms = "" - if name.find(" -> ") != -1: + if filename[-1] == "*": + filename = filename.rstrip("*") + if filename.find(" -> ") != -1: islink = 1 - filename, link = name.split(" -> ") - elif name[-1] == "*": - isaltered = 1 - filename = name.rstrip("*") - else: - filename = name - if name[-1] == "/": + filename, link = filename.split(" -> ") + elif filename.find("|") != -1: + setperms = 1 + filename, perms = filename.split("|") + if filename[-1] == "/": isdir = 1 if isdir: @@ -114,6 +114,8 @@ def mkfile(name, data = ""): if data[-1] != "\n": fd.write("\n") fd.close() + if setperms: + os.chmod(filename, int(perms, 8)) def mkdescfile(filename, pkg): """ @@ -181,7 +183,7 @@ def mkcfgfile(filename, root, option, db): # Repositories data.extend(["[%s]\n" \ - "server = file://%s\n" \ + "Server = file://%s\n" \ % (value.treename, \ os.path.join(root, SYNCREPO, value.treename)) \ for key, value in db.iteritems() if key != "local"]) diff --git a/po/POTFILES.in b/po/POTFILES.in index 359a8041..cf6e9506 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,7 +1,6 @@ # List of source files with translatable strings # pacman frontend source files -src/pacman/add.c src/pacman/callback.c src/pacman/conf.c src/pacman/deptest.c @@ -11,11 +10,10 @@ src/pacman/query.c src/pacman/remove.c src/pacman/sync.c src/pacman/util.c +src/pacman/upgrade.c # scripts with gettext translations -scripts/gensync.sh.in scripts/makepkg.sh.in scripts/pacman-optimize.sh.in scripts/repo-add.sh.in scripts/repo-remove.sh.in -scripts/updatesync.sh.in diff --git a/scripts/.gitignore b/scripts/.gitignore index 53164a41..f2f19fd8 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -1,7 +1,5 @@ -gensync makepkg pacman-optimize rankmirrors repo-add repo-remove -updatesync diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 24b9c12d..3185a476 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -2,22 +2,18 @@ AUTOMAKE_OPTIONS = std-options bin_SCRIPTS = \ - gensync \ makepkg \ pacman-optimize \ rankmirrors \ repo-add \ - repo-remove \ - updatesync + repo-remove EXTRA_DIST = \ - gensync.sh.in \ makepkg.sh.in \ pacman-optimize.sh.in \ rankmirrors.py.in \ repo-add.sh.in \ - repo-remove.sh.in \ - updatesync.sh.in + repo-remove.sh.in # Files that should be removed, but which Automake does not know. MOSTLYCLEANFILES = $(bin_SCRIPTS) *.tmp @@ -48,13 +44,11 @@ $(bin_SCRIPTS): Makefile chmod a-w $@.tmp mv $@.tmp $@ -gensync: $(srcdir)/gensync.sh.in makepkg: $(srcdir)/makepkg.sh.in pacman-optimize: $(srcdir)/pacman-optimize.sh.in rankmirrors: $(srcdir)/rankmirrors.py.in repo-add: $(srcdir)/repo-add.sh.in repo-remove: $(srcdir)/repo-remove.sh.in re-pacman: $(srcdir)/re-pacman.sh.in -updatesync: $(srcdir)/updatesync.sh.in # vim:set ts=2 sw=2 noet: diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index 54676667..6e2f1ad5 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -33,18 +33,22 @@ export TEXTDOMAIN='pacman' export TEXTDOMAINDIR='@localedir@' +# file -i does not work on Mac OSX unless legacy mode is set +export COMMAND_MODE='legacy' + myver='@PACKAGE_VERSION@' confdir='@sysconfdir@' startdir="$PWD" srcdir="$startdir/src" pkgdir="$startdir/pkg" +known_options=('strip' 'docs' 'libtool' 'emptydirs' 'zipman' 'ccache' 'distcc' 'makeflags' 'force') +readonly -a known_options # Options ASROOT=0 CLEANUP=0 CLEANCACHE=0 DEP_BIN=0 -DEP_SRC=0 FORCE=0 INFAKEROOT=0 GENINTEG=0 @@ -182,25 +186,6 @@ check_option() { return fi - # BEGIN DEPRECATED - # TODO: This code should be removed in the next release of makepkg. - local needle=$(echo $1 | tr [:upper:] [:lower:]) - local opt - for opt in ${options[@]}; do - opt=$(echo $opt | tr [:upper:] [:lower:]) - if [ "$opt" = "no$needle" ]; then - warning "$(gettext "Options beginning with 'no' will be deprecated in the next version of makepkg!")" - plain "$(gettext "Please replace 'no' with '!': %s -> %s.")" "no$needle" "!$needle" - echo 'n' # Disabled - return - elif [ "$opt" = "keepdocs" -a "$needle" = "docs" ]; then - warning "$(gettext "Option 'keepdocs' may not work as intended. Please replace with 'docs'.")" - echo 'y' # Enabled - return - fi - done - # END DEPRECATED - # fall back to makepkg.conf options ret=$(in_opt_array "$1" ${OPTIONS[@]}) if [ "$ret" != '?' ]; then @@ -299,6 +284,20 @@ get_downloadclient() { echo "$agent" } +get_downloadcmd() { + local dlagent=$1 + local netfile=$2 + local file=$3 + + if echo "$dlagent" | grep -q "%u" ; then + local dlcmd=$(echo "$dlagent" | sed "s|%o|$file.part|" | sed "s|%u|$netfile|") + else + local dlcmd="$dlagent $netfile" + fi + + echo "$dlcmd" +} + check_deps() { [ $# -gt 0 ] || return @@ -325,7 +324,7 @@ handledeps() { striplist="$striplist $depstrip" done - if [ "$DEP_SRC" = "0" -a "$DEP_BIN" = "0" ]; then + if [ "$DEP_BIN" = "0" ]; then return $R_DEPS_MISSING fi @@ -344,40 +343,6 @@ handledeps() { error "$(gettext "Pacman failed to install missing dependencies.")" exit 1 # TODO: error code fi - elif [ "$DEP_SRC" = "1" ]; then - msg "$(gettext "Building missing dependencies...")" - - # install missing deps by building them from source. - # we look for each package name in $SRCROOT and build it. - if [ "$SRCROOT" = "" ]; then - error "$(gettext "Source root cannot be found - please make sure it is specified in %s.")" "$confdir/makepkg.conf" - exit 1 # TODO: error code - fi - - # TODO: handle version comparators (eg, glibc>=2.2.5) - for dep in $striplist; do - local candidates="$(find "$SRCROOT" -type d -name "$dep")" - if [ "$candidates" = "" ]; then - error "$(gettext "Could not find '%s' under %s")" "$dep" "$SRCROOT" - exit 1 # TODO: error code - fi - - local makepkg_opts='-i -c -b' - [ "$RMDEPS" = "1" ] && makepkg_opts="$makepkg_opts -r" - [ "$ASROOT" = "1" ] && makepkg_opts="$makepkg_opts --asroot" - local ret packagedir - for packagedir in $candidates; do - if [ -f "$packagedir/$BUILDSCRIPT" ]; then - cd "$packagedir" - ret=0 - PKGDEST="$PKGDEST" makepkg $makepkg_opts $PACMAN_OPTS || ret=$? - [ $ret -eq 0 ] && continue 2 - fi - done - - error "$(gettext "Failed to build '%s'")" "$dep" - exit 1 # TODO: error code - done fi # rerun any additional sh scripts found in /etc/profile.d/ @@ -407,7 +372,7 @@ resolve_deps() { # check deps again to make sure they were resolved deplist="$(check_deps $*)" [ "$deplist" = "" ] && return $R_DEPS_SATISFIED - elif [ "$DEP_BIN" = "1" -o "$DEP_SRC" = "1" ]; then + elif [ "$DEP_BIN" = "1" ]; then error "$(gettext "Failed to install all missing dependencies.")" fi @@ -433,10 +398,17 @@ remove_deps() { done msg "Removing installed dependencies..." + local ret=0 if [ "$ASROOT" = "0" ]; then - sudo pacman $PACMAN_OPTS -Rns $deplist + sudo pacman $PACMAN_OPTS -Rns $deplist || ret=$? else - pacman $PACMAN_OPTS -Rns $deplist + pacman $PACMAN_OPTS -Rns $deplist || ret=$? + fi + + # Fixes FS#10039 - exit cleanly as package has built successfully + if [ $ret -ne 0 ]; then + warning "$(gettext "Failed to remove installed dependencies.")" + return 0 fi } @@ -456,11 +428,13 @@ download_sources() { local file=$(strip_url "$netfile") if [ -f "$startdir/$file" ]; then msg2 "$(gettext "Found %s in build dir")" "$file" - cp -s --remove-destination "$startdir/$file" "$srcdir/" + rm -f "$srcdir/$file" + ln -s "$startdir/$file" "$srcdir/" continue elif [ -f "$SRCDEST/$file" ]; then msg2 "$(gettext "Using cached copy of %s")" "$file" - cp -s --remove-destination "$SRCDEST/$file" "$srcdir/" + rm -f "$srcdir/$file" + ln -s "$SRCDEST/$file" "$srcdir/" continue fi @@ -471,18 +445,22 @@ download_sources() { fi # find the client we should use for this URL - local dlclient=$(get_downloadclient $netfile) || exit $? + local dlclient=$(get_downloadclient "$netfile") || exit $? msg2 "$(gettext "Downloading %s...")" "$file" # fix flyspray bug #3289 local ret=0 - $dlclient "$netfile" || ret=$? + $(get_downloadcmd "$dlclient" "$netfile" "$file") || ret=$? if [ $ret -gt 0 ]; then error "$(gettext "Failure while downloading %s")" "$file" plain "$(gettext "Aborting...")" exit 1 fi - cp -s --remove-destination "$SRCDEST/$file" "$srcdir/" + if echo "$dlclient" | grep -q "%o" ; then + mv -f "$SRCDEST/$file.part" "$SRCDEST/$file" + fi + rm -f "$srcdir/$file" + ln -s "$SRCDEST/$file" "$srcdir/" done popd &>/dev/null @@ -647,8 +625,8 @@ extract_sources() { done if [ $EUID -eq 0 ]; then - # chown all source files to root.root - chown -R root.root "$srcdir" + # change perms of all source files to root user & root group + chown -R 0:0 "$srcdir" fi } @@ -716,37 +694,41 @@ tidy_install() { rm -rf ${DOC_DIRS[@]} fi - msg2 "$(gettext "Compressing man pages...")" - local manpage mandirs ext file link hardlinks hl - mandirs="usr/man usr/share/man usr/local/man usr/local/share/man opt/*/man" - find ${mandirs} -type f 2>/dev/null | while read manpage ; do - # check file still exists (potentially compressed with hard link) - if [ -f ${manpage} ]; then - ext="${manpage##*.}" - file="${manpage##*/}" - if [ "$ext" != "gz" -a "$ext" != "bz2" ]; then - # update symlinks to this manpage - find ${mandirs} -lname "$file" 2>/dev/null | while read link ; do - rm -f "$link" - ln -sf "${file}.gz" "${link}.gz" - done - # find hard links and remove them - # the '|| true' part keeps the script from bailing if find returned an - # error, such as when one of the man directories doesn't exist - hardlinks="$(find ${mandirs} \! -name "$file" -samefile "$manpage" 2>/dev/null)" || true - for hl in ${hardlinks}; do - rm -f "${hl}"; - done - # compress the original - gzip -9 "$manpage" - # recreate hard links removed earlier - for hl in ${hardlinks}; do - ln "${manpage}.gz" "${hl}.gz" - chmod 644 ${hl}.gz - done + if [ "$(check_option zipman)" = "y" ]; then + msg2 "$(gettext "Compressing man pages...")" + local manpage mandirs ext file link hardlinks hl + mandirs="usr/man usr/share/man usr/local/man usr/local/share/man opt/*/man" + find ${mandirs} -type f 2>/dev/null | + while read manpage ; do + # check file still exists (potentially compressed with hard link) + if [ -f ${manpage} ]; then + ext="${manpage##*.}" + file="${manpage##*/}" + if [ "$ext" != "gz" -a "$ext" != "bz2" ]; then + # update symlinks to this manpage + find ${mandirs} -lname "$file" 2>/dev/null | + while read link ; do + rm -f "$link" + ln -sf "${file}.gz" "${link}.gz" + done + # find hard links and remove them + # the '|| true' part keeps the script from bailing if find returned an + # error, such as when one of the man directories doesn't exist + hardlinks="$(find ${mandirs} \! -name "$file" -samefile "$manpage" 2>/dev/null)" || true + for hl in ${hardlinks}; do + rm -f "${hl}"; + done + # compress the original + gzip -9 "$manpage" + # recreate hard links removed earlier + for hl in ${hardlinks}; do + ln "${manpage}.gz" "${hl}.gz" + chmod 644 ${hl}.gz + done + fi fi - fi - done + done + fi if [ "$(check_option strip)" = "y" ]; then @@ -790,7 +772,7 @@ create_package() { else local packager="Unknown Packager" fi - local size=$(du -sb | awk '{print $1}') + local size=$(du -sk | awk '{print $1 * 1024}') # write the .PKGINFO file msg2 "$(gettext "Generating .PKGINFO file...")" @@ -849,7 +831,6 @@ create_package() { local comp_files=".PKGINFO" # check for an install script - # TODO: should we include ${pkgname}.install if it exists and $install is unset? if [ "$install" != "" ]; then msg2 "$(gettext "Adding install script...")" cp "$startdir/$install" .INSTALL @@ -1071,7 +1052,6 @@ usage() { echo echo "$(gettext "Options:")" printf "$(gettext " -A, --ignorearch Ignore incomplete arch field in %s")\n" "$BUILDSCRIPT" - echo "$(gettext " -b, --builddeps Build missing dependencies from source")" echo "$(gettext " -c, --clean Clean up work files after build")" echo "$(gettext " -C, --cleancache Clean up source files from the cache")" echo "$(gettext " -d, --nodeps Skip all dependency checks")" @@ -1167,7 +1147,6 @@ while true; do # Makepkg Options --asroot) ASROOT=1 ;; -A|--ignorearch) IGNOREARCH=1 ;; - -b|--builddeps) DEP_SRC=1 ;; -c|--clean) CLEANUP=1 ;; -C|--cleancache) CLEANCACHE=1 ;; -d|--nodeps) NODEPS=1 ;; @@ -1276,7 +1255,7 @@ else fi # check for sudo if we will need it during makepkg execution -if [ "$ASROOT" = "0" -a \( "$DEP_BIN" = "1" -o "$DEP_SRC" = "1" \ +if [ "$ASROOT" = "0" -a \( "$DEP_BIN" = "1" \ -o "$RMDEPS" = "1" -o "$INSTALL" = "1" \) ]; then if [ ! "$(type -p sudo)" ]; then error "$(gettext "Cannot find the sudo binary! Is sudo installed?")" @@ -1348,6 +1327,25 @@ if [ "$install" -a ! -f "$install" ]; then exit 1 fi +valid_options=1 +for opt in ${options[@]}; do + known=0 + # check if option matches a known option or its inverse + for kopt in ${known_options[@]}; do + if [ "${opt}" = "${kopt}" -o "${opt}" = "!${kopt}" ]; then + known=1 + fi + done + if [ $known -eq 0 ]; then + error "$(gettext "options array contains unknown option '%s'")" "$opt" + valid_options=0 + fi +done +if [ $valid_options -eq 0 ]; then + exit 1 +fi +unset valid_options opt known kopt + # We need to run devel_update regardless of whether we are in the fakeroot # build process so that if the user runs makepkg --forcever manually, we # 1) output the correct pkgver, and 2) use the correct filename when @@ -1383,7 +1381,7 @@ if [ "$INFAKEROOT" = "1" ]; then exit 0 # $E_OK fi -msg "$(gettext "Making package: %s")" "$pkgname $pkgver-$pkgrel ($(date))" +msg "$(gettext "Making package: %s")" "$pkgname $pkgver-$pkgrel $CARCH ($(date))" if [ $EUID -eq 0 ]; then warning "$(gettext "Running makepkg as root...")" @@ -1470,8 +1468,8 @@ else mkdir -p "$pkgdir" cd "$startdir" - if [ $EUID -eq 0 ]; then - # if we are root, then we don't need to recall makepkg with fakeroot + if [ "$(check_buildenv fakeroot)" != "y" -o $EUID -eq 0 ]; then + # if we are root or if fakeroot is not enabled, then we don't use it if [ "$REPKG" = "1" ]; then warning "$(gettext "Skipping build.")" else @@ -1494,7 +1492,7 @@ else create_xdelta "$PKGDEST/${pkgname}-${pkgver}-${pkgrel}-${CARCH}${PKGEXT}" fi -msg "$(gettext "Finished making: %s")" "$pkgname ($(date))" +msg "$(gettext "Finished making: %s")" "$pkgname $pkgver-$pkgrel $CARCH ($(date))" install_package diff --git a/scripts/repo-add.sh.in b/scripts/repo-add.sh.in index 63d94d37..e90f0e89 100644 --- a/scripts/repo-add.sh.in +++ b/scripts/repo-add.sh.in @@ -3,7 +3,7 @@ # repo-add - add a package to a given repo database file # @configure_input@ # -# Copyright (c) 2006 Aaron Griffin <aaron@archlinux.org> +# Copyright (c) 2006-2008 Aaron Griffin <aaron@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 @@ -25,18 +25,20 @@ export TEXTDOMAINDIR='@localedir@' myver='@PACKAGE_VERSION@' confdir='@sysconfdir@' -FORCE=0 +QUIET=0 REPO_DB_FILE="" # ensure we have a sane umask set umask 0022 msg() { + [ $QUIET -ne 0 ] && return local mesg=$1; shift printf "==> ${mesg}\n" "$@" >&1 } msg2() { + [ $QUIET -ne 0 ] && return local mesg=$1; shift printf " -> ${mesg}\n" "$@" >&1 } @@ -54,21 +56,20 @@ error() { # print usage instructions usage() { printf "repo-add (pacman) %s\n\n" "$myver" - printf "$(gettext "Usage: %s <path-to-db> [--force] <package> ...\n\n")" "$0" + printf "$(gettext "Usage: %s [-q] <path-to-db> <package> ...\n\n")" "$0" 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 "\ -The --force flag will add a 'force' entry to the sync database, which\n\ -tells pacman to skip its internal version number checking and update\n\ -the package regardless.\n\n")" +The -q/--quiet flag will force this program to run silently except\n\ +in the case of warnings or errors.\n\n")" echo "$(gettext "Example: repo-add /path/to/repo.db.tar.gz pacman-3.0.0.pkg.tar.gz")" } version() { printf "repo-add (pacman) %s\n" "$myver" printf "$(gettext "\ -Copyright (C) 2006 Aaron Griffin <aaron@archlinux.org>.\n\n\ +Copyright (C) 2006-2008 Aaron Griffin <aaron@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")" } @@ -117,7 +118,7 @@ db_write_delta() # get md5sum and size of delta md5sum="$(md5sum "$deltafile" | cut -d ' ' -f 1)" - csize=$(du -b -L "$deltafile" | cut -f 1) + csize=$(du -kL "$deltafile" | awk '{print $1 * 1024}') # ensure variables were found if [ -z "$pkgname" -o -z "$fromver" -o -z "$tover" -o -z "$arch" ]; then @@ -164,7 +165,7 @@ db_write_entry() IFS=$OLDIFS # get compressed size of package - csize=$(du -b -L "$pkgfile" | cut -f 1) + csize=$(du -kL "$pkgfile" | awk '{print $1 * 1024}') startdir=$(pwd) pushd "$gstmpdir" 2>&1 >/dev/null @@ -209,7 +210,7 @@ db_write_entry() [ -n "$builddate" ] && echo -e "%BUILDDATE%\n$builddate\n" >>desc [ -n "$packager" ] && echo -e "%PACKAGER%\n$packager\n" >>desc write_list_entry "REPLACES" "$_replaces" "desc" - [ $FORCE -eq 1 -o -n "$force" ] && echo -e "%FORCE%\n" >>desc + [ -n "$force" ] && echo -e "%FORCE%\n" >>desc # create depends entry msg2 "$(gettext "Creating 'depends' db entry...")" @@ -236,7 +237,7 @@ db_write_entry() if db_write_delta "$delta"; then msg2 "$(gettext "Added delta '%s'")" "$(basename "$delta")" else - msg2 "$(gettext "Could not add delta '%s'")" "$(basename "$delta")" + warning "$(gettext "Could not add delta '%s'")" "$(basename "$delta")" fi fi done @@ -298,7 +299,10 @@ success=0 # parse arguments for arg in "$@"; do if [ "$arg" == "--force" -o "$arg" == "-f" ]; then - FORCE=1 + warning "$(gettext "the -f and --force options are no longer recognized")" + msg2 "$(gettext "use options=(force) in the PKGBUILD instead")" + elif [ "$arg" == "--quiet" -o "$arg" == "-q" ]; then + QUIET=1 elif [ -z "$REPO_DB_FILE" ]; then REPO_DB_FILE=$(readlink -f "$arg") if ! test_repo_db_file; then diff --git a/scripts/repo-remove.sh.in b/scripts/repo-remove.sh.in index 47a0d5ae..08786eec 100644 --- a/scripts/repo-remove.sh.in +++ b/scripts/repo-remove.sh.in @@ -3,7 +3,7 @@ # repo-remove - remove a package entry from a given repo database file # @configure_input@ # -# Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org> +# Copyright (c) 2007-2008 Dan McGee <dan@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 @@ -25,14 +25,17 @@ export TEXTDOMAINDIR='@localedir@' myver='@PACKAGE_VERSION@' confdir='@sysconfdir@' +QUIET=0 REPO_DB_FILE="" msg() { + [ $QUIET -ne 0 ] && return local mesg=$1; shift printf "==> ${mesg}\n" "$@" >&1 } msg2() { + [ $QUIET -ne 0 ] && return local mesg=$1; shift printf " -> ${mesg}\n" "$@" >&1 } @@ -50,18 +53,21 @@ error() { # print usage instructions usage() { printf "$(gettext "repo-remove %s\n\n")" $myver - printf "$(gettext "usage: %s <path-to-db> <packagename> ...\n\n")" "$0" + printf "$(gettext "usage: %s [-q] <path-to-db> <packagename> ...\n\n")" "$0" 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 "\ +The -q/--quiet flag will force this program to run silently except\n\ +in the case of warnings or errors.\n\n")" echo "$(gettext "Example: repo-remove /path/to/repo.db.tar.gz kernel26")" } version() { printf "repo-remove (pacman) %s\n" "$myver" printf "$(gettext "\ -Copyright (C) 2002-2007 Judd Vinet <jvinet@zeroflux.org>.\n\n\ +Copyright (c) 2007-2008 Dan McGee <dan@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")" } @@ -140,7 +146,9 @@ gstmpdir=$(mktemp -d /tmp/repo-remove.XXXXXXXXXX) || (\ success=0 # parse arguments for arg in "$@"; do - if [ -z "$REPO_DB_FILE" ]; then + if [ "$arg" == "--quiet" -o "$arg" == "-q" ]; then + QUIET=1 + elif [ -z "$REPO_DB_FILE" ]; then REPO_DB_FILE=$(readlink -f "$arg") if ! test_repo_db_file; then error "$(gettext "Repository file '%s' is not a proper pacman database.")\n" "$REPO_DB_FILE" diff --git a/src/pacman/Makefile.am b/src/pacman/Makefile.am index 5e287404..5d6fef3c 100644 --- a/src/pacman/Makefile.am +++ b/src/pacman/Makefile.am @@ -22,7 +22,6 @@ INCLUDES = -I$(top_srcdir)/lib/libalpm AM_CFLAGS = -pedantic -D_GNU_SOURCE pacman_SOURCES = \ - add.c \ conf.h conf.c \ deptest.c \ package.h package.c \ @@ -31,6 +30,7 @@ pacman_SOURCES = \ remove.c \ sync.c \ callback.h callback.c \ + upgrade.c \ util.h util.c LDADD = $(LTLIBINTL) $(top_builddir)/lib/libalpm/.libs/libalpm.la diff --git a/src/pacman/callback.c b/src/pacman/callback.c index a7686483..4c415e1a 100644 --- a/src/pacman/callback.c +++ b/src/pacman/callback.c @@ -34,9 +34,6 @@ #include "util.h" #include "conf.h" -/* TODO this should not have to be defined twice- trans.c & log.c */ -#define LOG_STR_LEN 256 - /* download progress bar */ static float rate_last; static int xfered_last; @@ -86,17 +83,14 @@ static float get_update_timediff(int first_call) } /* refactored from cb_trans_progress */ -static void fill_progress(const int graph_percent, const int display_percent, - const int proglen) +static void fill_progress(const int percent, const int proglen) { const unsigned int hashlen = proglen - 8; - const unsigned int hash = graph_percent * hashlen / 100; + const unsigned int hash = percent * hashlen / 100; static unsigned int lasthash = 0, mouth = 0; unsigned int i; - /* printf("\ndebug: proglen: %i\n", proglen); DEBUG*/ - - if(graph_percent == 0) { + if(percent == 0) { lasthash = 0; mouth = 0; } @@ -141,10 +135,10 @@ static void fill_progress(const int graph_percent, const int display_percent, } /* print percent after progress bar */ if(proglen > 5) { - printf(" %3d%%", display_percent); + printf(" %3d%%", percent); } - if(graph_percent == 100) { + if(percent == 100) { printf("\n"); } else { printf("\r"); @@ -157,8 +151,6 @@ static void fill_progress(const int graph_percent, const int display_percent, /* callback to handle messages/notifications from libalpm transactions */ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2) { - char str[LOG_STR_LEN] = ""; - switch(event) { case PM_TRANS_EVT_CHECKDEPS_START: printf(_("checking dependencies...\n")); @@ -180,10 +172,9 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2) } break; case PM_TRANS_EVT_ADD_DONE: - snprintf(str, LOG_STR_LEN, "installed %s (%s)\n", + alpm_logaction("installed %s (%s)\n", alpm_pkg_get_name(data1), alpm_pkg_get_version(data1)); - alpm_logaction(str); break; case PM_TRANS_EVT_REMOVE_START: if(config->noprogressbar) { @@ -191,10 +182,9 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2) } break; case PM_TRANS_EVT_REMOVE_DONE: - snprintf(str, LOG_STR_LEN, "removed %s (%s)\n", + alpm_logaction("removed %s (%s)\n", alpm_pkg_get_name(data1), alpm_pkg_get_version(data1)); - alpm_logaction(str); break; case PM_TRANS_EVT_UPGRADE_START: if(config->noprogressbar) { @@ -202,11 +192,10 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2) } break; case PM_TRANS_EVT_UPGRADE_DONE: - snprintf(str, LOG_STR_LEN, "upgraded %s (%s -> %s)\n", + alpm_logaction("upgraded %s (%s -> %s)\n", (char *)alpm_pkg_get_name(data1), (char *)alpm_pkg_get_version(data2), (char *)alpm_pkg_get_version(data1)); - alpm_logaction(str); break; case PM_TRANS_EVT_INTEGRITY_START: printf(_("checking package integrity...\n")); @@ -237,7 +226,6 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2) break; /* all the simple done events, with fallthrough for each */ case PM_TRANS_EVT_FILECONFLICTS_DONE: - case PM_TRANS_EVT_EXTRACT_DONE: case PM_TRANS_EVT_CHECKDEPS_DONE: case PM_TRANS_EVT_RESOLVEDEPS_DONE: case PM_TRANS_EVT_INTERCONFLICTS_DONE: @@ -255,67 +243,46 @@ void cb_trans_evt(pmtransevt_t event, void *data1, void *data2) void cb_trans_conv(pmtransconv_t event, void *data1, void *data2, void *data3, int *response) { - char str[LOG_STR_LEN] = ""; - switch(event) { case PM_TRANS_CONV_INSTALL_IGNOREPKG: if(data2) { /* TODO we take this route based on data2 being not null? WTF */ - snprintf(str, LOG_STR_LEN, _(":: %s requires installing %s from IgnorePkg/IgnoreGroup. Install anyway? [Y/n] "), + *response = yesno(1, _(":: %s requires installing %s from IgnorePkg/IgnoreGroup. Install anyway?"), alpm_pkg_get_name(data1), alpm_pkg_get_name(data2)); - *response = yesno(str); } else { - snprintf(str, LOG_STR_LEN, _(":: %s is in IgnorePkg/IgnoreGroup. Install anyway? [Y/n] "), + *response = yesno(1, _(":: %s is in IgnorePkg/IgnoreGroup. Install anyway?"), alpm_pkg_get_name(data1)); - *response = yesno(str); } break; case PM_TRANS_CONV_REMOVE_HOLDPKG: - snprintf(str, LOG_STR_LEN, _(":: %s is designated as a HoldPkg. Remove anyway? [Y/n] "), + *response = yesno(1, _(":: %s is designated as a HoldPkg. Remove anyway?"), alpm_pkg_get_name(data1)); - *response = yesno(str); break; case PM_TRANS_CONV_REPLACE_PKG: - if(!config->noconfirm) { - snprintf(str, LOG_STR_LEN, _(":: Replace %s with %s/%s? [Y/n] "), - alpm_pkg_get_name(data1), - (char *)data3, - alpm_pkg_get_name(data2)); - *response = yesno(str); - } else { - printf(_("Replacing %s with %s/%s\n"), - alpm_pkg_get_name(data1), - (char *)data3, - alpm_pkg_get_name(data2)); - *response = 1; - } + *response = yesno(1, _(":: Replace %s with %s/%s?"), + alpm_pkg_get_name(data1), + (char *)data3, + alpm_pkg_get_name(data2)); break; case PM_TRANS_CONV_CONFLICT_PKG: - snprintf(str, LOG_STR_LEN, _(":: %s conflicts with %s. Remove %s? [Y/n] "), + *response = yesno(1, _(":: %s conflicts with %s. Remove %s?"), (char *)data1, (char *)data2, (char *)data2); - *response = yesno(str); break; case PM_TRANS_CONV_LOCAL_NEWER: if(!config->op_s_downloadonly) { - snprintf(str, LOG_STR_LEN, _(":: %s-%s: local version is newer. Upgrade anyway? [Y/n] "), + *response = yesno(1, _(":: %s-%s: local version is newer. Upgrade anyway?"), alpm_pkg_get_name(data1), alpm_pkg_get_version(data1)); - *response = yesno(str); } else { *response = 1; } break; case PM_TRANS_CONV_CORRUPTED_PKG: - if(!config->noconfirm) { - snprintf(str, LOG_STR_LEN, _(":: File %s is corrupted. Do you want to delete it? [Y/n] "), - (char *)data1); - *response = yesno(str); - } else { - *response = 1; - } + *response = yesno(1, _(":: File %s is corrupted. Do you want to delete it?"), + (char *)data1); break; } } @@ -427,7 +394,7 @@ void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent, free(wcstr); /* call refactored fill progress function */ - fill_progress(percent, percent, getcols() - infolen); + fill_progress(percent, getcols() - infolen); if(percent == 100) { alpm_list_t *i = NULL; @@ -443,8 +410,7 @@ void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent, } /* callback to handle display of download progress */ -void cb_dl_progress(const char *filename, int file_xfered, int file_total, - int list_xfered, int list_total) +void cb_dl_progress(const char *filename, int xfered, int total) { const int infolen = 50; const int filenamelen = infolen - 27; @@ -455,43 +421,22 @@ void cb_dl_progress(const char *filename, int file_xfered, int file_total, float rate = 0.0, timediff = 0.0, f_xfered = 0.0; unsigned int eta_h = 0, eta_m = 0, eta_s = 0; - int graph_percent = 0, display_percent = 0; + int percent; char rate_size = 'K', xfered_size = 'K'; - int xfered = 0, total = 0; - - /* Need this variable when TotalDownload is set to know if we should - * reset xfered_last and rate_last. */ - static int has_init = 0; if(config->noprogressbar) { return; } - /* Choose how to display the amount downloaded, rate, ETA, and - * percentage depending on the TotalDownload option. */ - if (config->totaldownload && list_total > 0) { - xfered = list_xfered; - total = list_total; - } else { - xfered = file_xfered; - total = file_total; - } - /* this is basically a switch on file_xferred: 0, file_total, and * anything else */ - if(file_xfered == 0) { - /* set default starting values, but only once for TotalDownload */ - if (!(config->totaldownload && list_total > 0) || - (config->totaldownload && list_total > 0 && !has_init)) { - gettimeofday(&initial_time, NULL); - timediff = get_update_timediff(1); - xfered_last = 0; - rate_last = 0.0; - has_init = 1; - } - rate = 0.0; - eta_s = 0; - } else if(file_xfered == file_total) { + if(xfered == 0) { + /* set default starting values */ + gettimeofday(&initial_time, NULL); + xfered_last = 0; + rate_last = 0.0; + timediff = get_update_timediff(1); + } else if(xfered == total) { /* compute final values */ struct timeval current_time; float diff_sec, diff_usec; @@ -500,7 +445,7 @@ void cb_dl_progress(const char *filename, int file_xfered, int file_total, diff_sec = current_time.tv_sec - initial_time.tv_sec; diff_usec = current_time.tv_usec - initial_time.tv_usec; timediff = diff_sec + (diff_usec / 1000000.0); - rate = xfered / (timediff * 1024.0); + rate = total / (timediff * 1024.0); /* round elapsed time to the nearest second */ eta_s = (int)(timediff + 0.5); @@ -514,12 +459,14 @@ void cb_dl_progress(const char *filename, int file_xfered, int file_total, } rate = (xfered - xfered_last) / (timediff * 1024.0); /* average rate to reduce jumpiness */ - rate = (rate + 2*rate_last) / 3; + rate = (rate + 2 * rate_last) / 3; eta_s = (total - xfered) / (rate * 1024.0); rate_last = rate; xfered_last = xfered; } + percent = (int)((float)xfered) / ((float)total) * 100; + /* fix up time for display */ eta_h = eta_s / 3600; eta_s -= eta_h * 3600; @@ -591,11 +538,7 @@ void cb_dl_progress(const char *filename, int file_xfered, int file_total, free(fname); free(wcfname); - /* The progress bar is based on the file percent regardless of the - * TotalDownload option. */ - graph_percent = (int)((float)file_xfered) / ((float)file_total) * 100; - display_percent = (int)((float)xfered) / ((float)total) * 100; - fill_progress(graph_percent, display_percent, getcols() - infolen); + fill_progress(percent, getcols() - infolen); return; } diff --git a/src/pacman/callback.h b/src/pacman/callback.h index aa8d9370..39d59d8b 100644 --- a/src/pacman/callback.h +++ b/src/pacman/callback.h @@ -33,8 +33,7 @@ void cb_trans_progress(pmtransprog_t event, const char *pkgname, int percent, int howmany, int remain); /* callback to handle display of download progress */ -void cb_dl_progress(const char *filename, int file_xfered, int file_total, - int list_xfered, int list_total); +void cb_dl_progress(const char *filename, int file_xfered, int file_total); /* callback to handle messages/notifications from pacman library */ void cb_log(pmloglevel_t level, char *fmt, va_list args); diff --git a/src/pacman/conf.c b/src/pacman/conf.c index bf3a4624..48c927bf 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -25,6 +25,7 @@ /* pacman */ #include "conf.h" +#include "util.h" /* global config variable */ config_t *config = NULL; @@ -33,8 +34,9 @@ config_t *config_new(void) { config_t *newconfig = calloc(1, sizeof(config_t)); if(!newconfig) { - fprintf(stderr, "malloc failure: could not allocate %zd bytes\n", - sizeof(config_t)); + pm_fprintf(stderr, PM_LOG_ERROR, + _("malloc failure: could not allocate %zd bytes\n"), + sizeof(config_t)); return(NULL); } /* defaults which may get overridden later */ @@ -45,6 +47,7 @@ config_t *config_new(void) newconfig->rootdir = NULL; newconfig->dbpath = NULL; newconfig->logfile = NULL; + newconfig->syncfirst = NULL; return(newconfig); } @@ -55,6 +58,7 @@ int config_free(config_t *oldconfig) return(-1); } + FREELIST(oldconfig->syncfirst); free(oldconfig->configfile); free(oldconfig->rootdir); free(oldconfig->dbpath); diff --git a/src/pacman/conf.h b/src/pacman/conf.h index f804f560..874ce708 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -27,7 +27,6 @@ typedef struct __config_t { unsigned short verbose; unsigned short version; unsigned short help; - unsigned short upgrade; unsigned short noconfirm; unsigned short noprogressbar; unsigned short logmask; @@ -53,7 +52,6 @@ typedef struct __config_t { unsigned short op_q_upgrade; unsigned short op_s_clean; - unsigned short op_s_dependsonly; unsigned short op_s_downloadonly; unsigned short op_s_info; unsigned short op_s_sync; @@ -67,15 +65,16 @@ typedef struct __config_t { unsigned short chomp; /* I Love Candy! */ unsigned short usecolor; /* enable colorful output */ unsigned short showsize; /* show individual package sizes */ - unsigned short totaldownload; /* When downloading, display the amount - downloaded, rate, ETA, and percent - downloaded of the total download list */ + /* When downloading, display the amount downloaded, rate, ETA, and percent + * downloaded of the total download list */ + unsigned short totaldownload; + unsigned short cleanmethod; /* select -Sc behavior */ + alpm_list_t *syncfirst; } config_t; /* Operations */ enum { PM_OP_MAIN = 1, - PM_OP_ADD, PM_OP_REMOVE, PM_OP_UPGRADE, PM_OP_QUERY, @@ -83,6 +82,12 @@ enum { PM_OP_DEPTEST }; +/* clean method */ +enum { + PM_CLEAN_KEEPINST = 0, /* default */ + PM_CLEAN_KEEPCUR +}; + /* global config variable */ extern config_t *config; diff --git a/src/pacman/deptest.c b/src/pacman/deptest.c index 2481c0b6..2feca5c4 100644 --- a/src/pacman/deptest.c +++ b/src/pacman/deptest.c @@ -31,53 +31,23 @@ #include "util.h" #include "conf.h" -/* TODO: This should use _alpm_checkdeps() */ int pacman_deptest(alpm_list_t *targets) { - int retval = 0; alpm_list_t *i; - if(targets == NULL) { + alpm_list_t *deps = alpm_deptest(alpm_option_get_localdb(), targets); + if(deps == NULL) { return(0); } - for(i = targets; i; i = alpm_list_next(i)) { - int found = 0; - pmpkg_t *pkg; - pmdepend_t *dep; - const char *target; - alpm_list_t *j, *provides; + for(i = deps; i; i = alpm_list_next(i)) { + const char *dep; - target = alpm_list_getdata(i); - dep = alpm_splitdep(target); - - pkg = alpm_db_get_pkg(alpm_option_get_localdb(), - alpm_dep_get_name(dep)); - if(pkg && alpm_depcmp(pkg, dep)) { - found = 1; - } else { - /* not found, can we find anything that provides this in the local DB? */ - provides = alpm_db_whatprovides(alpm_option_get_localdb(), - alpm_dep_get_name(dep)); - for(j = provides; j; j = alpm_list_next(j)) { - pmpkg_t *pkg; - pkg = alpm_list_getdata(j); - - if(pkg && alpm_depcmp(pkg, dep)) { - found = 1; - break; - } - } - alpm_list_free(provides); - } - - if(!found) { - printf("%s\n", target); - retval = 127; - } - free(dep); + dep = alpm_list_getdata(i); + printf("%s\n", dep); } - return(retval); + alpm_list_free(deps); + return(127); } /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/package.c b/src/pacman/package.c index 7019e7e6..21213c4a 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -195,8 +195,8 @@ void dump_pkg_backups(pmpkg_t *pkg) char *md5sum = alpm_get_md5sum(path); if(md5sum == NULL) { - fprintf(stderr, _("error: could not calculate checksums for %s\n"), - path); + pm_fprintf(stderr, PM_LOG_ERROR, + _("could not calculate checksums for %s\n"), path); free(str); continue; } @@ -225,17 +225,14 @@ void dump_pkg_files(pmpkg_t *pkg) { const char *pkgname, *root, *filestr; alpm_list_t *i, *pkgfiles; - char path[PATH_MAX]; pkgname = alpm_pkg_get_name(pkg); pkgfiles = alpm_pkg_get_files(pkg); root = alpm_option_get_root(); for(i = pkgfiles; i; i = alpm_list_next(i)) { - filestr = (char*)alpm_list_getdata(i); - /* build a path so we can stat the filename */ - snprintf(path, PATH_MAX-1, "%s%s", root, filestr); - fprintf(stdout, "%s %s\n", pkgname, path); + filestr = alpm_list_getdata(i); + fprintf(stdout, "%s %s%s\n", pkgname, root, filestr); } fflush(stdout); @@ -248,8 +245,7 @@ void dump_pkg_changelog(pmpkg_t *pkg) void *fp = NULL; if((fp = alpm_pkg_changelog_open(pkg)) == NULL) { - /* TODO after string freeze use pm_fprintf */ - fprintf(stderr, _("error: no changelog available for '%s'.\n"), + pm_fprintf(stderr, PM_LOG_ERROR, _("no changelog available for '%s'.\n"), alpm_pkg_get_name(pkg)); return; } else { diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index c2b61fcd..66fafa10 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -68,31 +68,27 @@ static void usage(int op, const char * const myname) printf("%s:\n", str_opt); printf(" %s {-h --help}\n", myname); printf(" %s {-V --version}\n", myname); - printf(" %s {-A --add} [%s] <%s>\n", myname, str_opt, str_file); printf(" %s {-Q --query} [%s] [%s]\n", myname, str_opt, str_pkg); printf(" %s {-R --remove} [%s] <%s>\n", myname, str_opt, str_pkg); printf(" %s {-S --sync} [%s] [%s]\n", myname, str_opt, str_pkg); printf(" %s {-U --upgrade} [%s] <%s>\n", myname, str_opt, str_file); printf(_("\nuse '%s --help' with other options for more syntax\n"), myname); } else { - if(op == PM_OP_ADD) { - printf("%s: %s {-A --add} [%s] <%s>\n", str_usg, myname, str_opt, str_file); - printf("%s:\n", str_opt); - printf(_(" --asdeps install packages as non-explicitly installed\n")); - printf(_(" -d, --nodeps skip dependency checks\n")); - printf(_(" -f, --force force install, overwrite conflicting files\n")); - } else if(op == PM_OP_REMOVE) { + if(op == PM_OP_REMOVE) { printf("%s: %s {-R --remove} [%s] <%s>\n", str_usg, myname, str_opt, str_pkg); printf("%s:\n", str_opt); printf(_(" -c, --cascade remove packages and all packages that depend on them\n")); printf(_(" -d, --nodeps skip dependency checks\n")); printf(_(" -k, --dbonly only remove database entry, do not remove files\n")); printf(_(" -n, --nosave remove configuration files as well\n")); - printf(_(" -s, --recursive remove dependencies also (that won't break packages)\n")); + printf(_(" -s, --recursive remove dependencies also (that won't break packages)\n" + " (-ss includes explicitly installed dependencies too)\n")); + printf(_(" -u, --unneeded remove unneeded packages (that won't break packages)\n")); } else if(op == PM_OP_UPGRADE) { printf("%s: %s {-U --upgrade} [%s] <%s>\n", str_usg, myname, str_opt, str_file); printf("%s:\n", str_opt); printf(_(" --asdeps install packages as non-explicitly installed\n")); + printf(_(" --asexplicit install packages as explicitly installed\n")); printf(_(" -d, --nodeps skip dependency checks\n")); printf(_(" -f, --force force install, overwrite conflicting files\n")); } else if(op == PM_OP_QUERY) { @@ -115,9 +111,9 @@ static void usage(int op, const char * const myname) printf("%s: %s {-S --sync} [%s] [%s]\n", str_usg, myname, str_opt, str_pkg); printf("%s:\n", str_opt); printf(_(" --asdeps install packages as non-explicitly installed\n")); + printf(_(" --asexplicit install packages as explicitly installed\n")); printf(_(" -c, --clean remove old packages from cache directory (-cc for all)\n")); printf(_(" -d, --nodeps skip dependency checks\n")); - printf(_(" -e, --dependsonly install dependencies only\n")); printf(_(" -f, --force force install, overwrite conflicting files\n")); printf(_(" -g, --groups view all members of a package group\n")); printf(_(" -i, --info view package information\n")); @@ -212,14 +208,15 @@ static void cleanup(int ret) { * in a consistant state. * @param signum the thrown signal */ -static void handler(int signum) +static RETSIGTYPE handler(int signum) { if(signum==SIGSEGV) { /* write a log message and write to stderr */ - pm_printf(PM_LOG_ERROR, "segmentation fault\n"); - pm_fprintf(stderr, PM_LOG_ERROR, "Internal pacman error: Segmentation fault.\n" - "Please submit a full bug report with --debug if appropriate.\n"); + pm_printf(PM_LOG_ERROR, _("segmentation fault\n")); + pm_fprintf(stderr, PM_LOG_ERROR, + _("Internal pacman error: Segmentation fault.\n" + "Please submit a full bug report with --debug if appropriate.\n")); exit(signum); } else if((signum == SIGINT)) { if(alpm_trans_interrupt() == 0) { @@ -305,7 +302,6 @@ static int parseargs(int argc, char *argv[]) int option_index = 0; static struct option opts[] = { - {"add", no_argument, 0, 'A'}, {"query", no_argument, 0, 'Q'}, {"remove", no_argument, 0, 'R'}, {"sync", no_argument, 0, 'S'}, @@ -318,7 +314,6 @@ static int parseargs(int argc, char *argv[]) {"clean", no_argument, 0, 'c'}, {"nodeps", no_argument, 0, 'd'}, {"deps", no_argument, 0, 'd'}, - {"dependsonly",no_argument, 0, 'e'}, {"explicit", no_argument, 0, 'e'}, {"force", no_argument, 0, 'f'}, {"groups", no_argument, 0, 'g'}, @@ -338,6 +333,7 @@ static int parseargs(int argc, char *argv[]) {"unrequired", no_argument, 0, 't'}, {"upgrades", no_argument, 0, 'u'}, {"sysupgrade", no_argument, 0, 'u'}, + {"unneeded", no_argument, 0, 'u'}, {"verbose", no_argument, 0, 'v'}, {"downloadonly", no_argument, 0, 'w'}, {"refresh", no_argument, 0, 'y'}, @@ -352,10 +348,11 @@ static int parseargs(int argc, char *argv[]) {"logfile", required_argument, 0, 1009}, {"ignoregroup", required_argument, 0, 1010}, {"needed", no_argument, 0, 1011}, + {"asexplicit", no_argument, 0, 1012}, {0, 0, 0, 0} }; - while((opt = getopt_long(argc, argv, "ARUFQSTr:b:vkhscVfmnoldepqituwygz", opts, &option_index))) { + while((opt = getopt_long(argc, argv, "RUFQSTr:b:vkhscVfmnoldepqituwygz", opts, &option_index))) { alpm_list_t *list = NULL, *item = NULL; /* lists for splitting strings */ if(opt < 0) { @@ -423,7 +420,9 @@ static int parseargs(int argc, char *argv[]) FREELIST(list); break; case 1011: config->flags |= PM_TRANS_FLAG_NEEDED; break; - case 'A': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_ADD); break; + case 1012: + config->flags |= PM_TRANS_FLAG_ALLEXPLICIT; + break; case 'Q': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_QUERY); break; case 'R': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_REMOVE); break; case 'S': config->op = (config->op != PM_OP_MAIN ? 0 : PM_OP_SYNC); break; @@ -444,7 +443,6 @@ static int parseargs(int argc, char *argv[]) break; case 'e': config->op_q_explicit = 1; - config->flags |= PM_TRANS_FLAG_DEPENDSONLY; break; case 'f': config->flags |= PM_TRANS_FLAG_FORCE; break; case 'g': (config->group)++; break; @@ -468,7 +466,11 @@ static int parseargs(int argc, char *argv[]) case 's': config->op_s_search = 1; config->op_q_search = 1; - config->flags |= PM_TRANS_FLAG_RECURSE; + if(config->flags & PM_TRANS_FLAG_RECURSE) { + config->flags |= PM_TRANS_FLAG_RECURSEALL; + } else { + config->flags |= PM_TRANS_FLAG_RECURSE; + } break; case 't': config->op_q_unrequired = 1; @@ -476,6 +478,7 @@ static int parseargs(int argc, char *argv[]) case 'u': config->op_s_upgrade = 1; config->op_q_upgrade = 1; + config->flags |= PM_TRANS_FLAG_UNNEEDED; break; case 'v': (config->verbose)++; break; case 'w': @@ -512,6 +515,11 @@ static int parseargs(int argc, char *argv[]) return(0); } +/* helper for being used with setrepeatingoption */ +static void option_add_syncfirst(const char *name) { + config->syncfirst = alpm_list_add(config->syncfirst, strdup(name)); +} + /** Add repeating options such as NoExtract, NoUpgrade, etc to libalpm * settings. Refactored out of the parseconfig code since all of them did * the exact same thing and duplicated code. @@ -599,7 +607,7 @@ static int _parseconfig(const char *file, const char *givensection, } } else { /* directive */ - char *key, *upperkey; + char *key; /* strsep modifies the 'line' string: 'key \0 ptr' */ key = line; ptr = line; @@ -612,11 +620,7 @@ static int _parseconfig(const char *file, const char *givensection, file, linenum); return(1); } - /* For each directive, compare to the uppercase and camelcase string. - * This prevents issues with certain locales where characters don't - * follow the toupper() rules we may expect, e.g. tr_TR where i != I. - */ - upperkey = strtoupper(strdup(key)); + /* For each directive, compare to the camelcase string. */ if(section == NULL) { pm_printf(PM_LOG_ERROR, _("config file %s, line %d: All directives must belong to a section.\n"), file, linenum); @@ -624,25 +628,25 @@ static int _parseconfig(const char *file, const char *givensection, } if(ptr == NULL && strcmp(section, "options") == 0) { /* directives without settings, all in [options] */ - if(strcmp(key, "NoPassiveFTP") == 0 || strcmp(upperkey, "NOPASSIVEFTP") == 0) { + if(strcmp(key, "NoPassiveFTP") == 0) { alpm_option_set_nopassiveftp(1); pm_printf(PM_LOG_DEBUG, "config: nopassiveftp\n"); - } else if(strcmp(key, "UseSyslog") == 0 || strcmp(upperkey, "USESYSLOG") == 0) { + } else if(strcmp(key, "UseSyslog") == 0) { alpm_option_set_usesyslog(1); pm_printf(PM_LOG_DEBUG, "config: usesyslog\n"); - } else if(strcmp(key, "ILoveCandy") == 0 || strcmp(upperkey, "ILOVECANDY") == 0) { + } else if(strcmp(key, "ILoveCandy") == 0) { config->chomp = 1; pm_printf(PM_LOG_DEBUG, "config: chomp\n"); - } else if(strcmp(key, "UseColor") == 0 || strcmp(upperkey, "USECOLOR") == 0) { + } else if(strcmp(key, "UseColor") == 0) { config->usecolor = 1; pm_printf(PM_LOG_DEBUG, "config: usecolor\n"); - } else if(strcmp(key, "ShowSize") == 0 || strcmp(upperkey, "SHOWSIZE") == 0) { + } else if(strcmp(key, "ShowSize") == 0) { config->showsize = 1; pm_printf(PM_LOG_DEBUG, "config: showsize\n"); - } else if(strcmp(key, "UseDelta") == 0 || strcmp(upperkey, "USEDELTA") == 0) { + } else if(strcmp(key, "UseDelta") == 0) { alpm_option_set_usedelta(1); pm_printf(PM_LOG_DEBUG, "config: usedelta\n"); - } else if(strcmp(key, "TotalDownload") == 0 || strcmp(upperkey, "TOTALDOWNLOAD") == 0) { + } else if(strcmp(key, "TotalDownload") == 0) { config->totaldownload = 1; pm_printf(PM_LOG_DEBUG, "config: totaldownload\n"); } else { @@ -652,59 +656,66 @@ static int _parseconfig(const char *file, const char *givensection, } } else { /* directives with settings */ - if(strcmp(key, "Include") == 0 || strcmp(upperkey, "INCLUDE") == 0) { + if(strcmp(key, "Include") == 0) { pm_printf(PM_LOG_DEBUG, "config: including %s\n", ptr); _parseconfig(ptr, section, db); /* Ignore include failures... assume non-critical */ } else if(strcmp(section, "options") == 0) { - if(strcmp(key, "NoUpgrade") == 0 - || strcmp(upperkey, "NOUPGRADE") == 0) { + if(strcmp(key, "NoUpgrade") == 0) { setrepeatingoption(ptr, "NoUpgrade", alpm_option_add_noupgrade); - } else if(strcmp(key, "NoExtract") == 0 - || strcmp(upperkey, "NOEXTRACT") == 0) { + } else if(strcmp(key, "NoExtract") == 0) { setrepeatingoption(ptr, "NoExtract", alpm_option_add_noextract); - } else if(strcmp(key, "IgnorePkg") == 0 - || strcmp(upperkey, "IGNOREPKG") == 0) { + } else if(strcmp(key, "IgnorePkg") == 0) { setrepeatingoption(ptr, "IgnorePkg", alpm_option_add_ignorepkg); - } else if(strcmp(key, "IgnoreGroup") == 0 - || strcmp(upperkey, "IGNOREGROUP") == 0) { + } else if(strcmp(key, "IgnoreGroup") == 0) { setrepeatingoption(ptr, "IgnoreGroup", alpm_option_add_ignoregrp); - } else if(strcmp(key, "HoldPkg") == 0 - || strcmp(upperkey, "HOLDPKG") == 0) { + } else if(strcmp(key, "HoldPkg") == 0) { setrepeatingoption(ptr, "HoldPkg", alpm_option_add_holdpkg); - } else if(strcmp(key, "DBPath") == 0 || strcmp(upperkey, "DBPATH") == 0) { + } else if(strcmp(key, "SyncFirst") == 0) { + setrepeatingoption(ptr, "SyncFirst", option_add_syncfirst); + } else if(strcmp(key, "DBPath") == 0) { /* don't overwrite a path specified on the command line */ if(!config->dbpath) { config->dbpath = strdup(ptr); pm_printf(PM_LOG_DEBUG, "config: dbpath: %s\n", ptr); } - } else if(strcmp(key, "CacheDir") == 0 || strcmp(upperkey, "CACHEDIR") == 0) { + } else if(strcmp(key, "CacheDir") == 0) { if(alpm_option_add_cachedir(ptr) != 0) { pm_printf(PM_LOG_ERROR, _("problem adding cachedir '%s' (%s)\n"), ptr, alpm_strerrorlast()); return(1); } pm_printf(PM_LOG_DEBUG, "config: cachedir: %s\n", ptr); - } else if(strcmp(key, "RootDir") == 0 || strcmp(upperkey, "ROOTDIR") == 0) { + } else if(strcmp(key, "RootDir") == 0) { /* don't overwrite a path specified on the command line */ if(!config->rootdir) { config->rootdir = strdup(ptr); pm_printf(PM_LOG_DEBUG, "config: rootdir: %s\n", ptr); } - } else if (strcmp(key, "LogFile") == 0 || strcmp(upperkey, "LOGFILE") == 0) { + } else if (strcmp(key, "LogFile") == 0) { if(!config->logfile) { config->logfile = strdup(ptr); pm_printf(PM_LOG_DEBUG, "config: logfile: %s\n", ptr); } - } else if (strcmp(key, "XferCommand") == 0 || strcmp(upperkey, "XFERCOMMAND") == 0) { + } else if (strcmp(key, "XferCommand") == 0) { alpm_option_set_xfercommand(ptr); pm_printf(PM_LOG_DEBUG, "config: xfercommand: %s\n", ptr); + } else if (strcmp(key, "CleanMethod") == 0) { + if (strcmp(ptr, "KeepInstalled") == 0) { + config->cleanmethod = PM_CLEAN_KEEPINST; + } else if (strcmp(ptr, "KeepCurrent") == 0) { + config->cleanmethod = PM_CLEAN_KEEPCUR; + } else { + pm_printf(PM_LOG_ERROR, _("invalid value for 'CleanMethod' : '%s'\n"), ptr); + return(1); + } + pm_printf(PM_LOG_DEBUG, "config: cleanmethod: %s\n", ptr); } else { pm_printf(PM_LOG_ERROR, _("config file %s, line %d: directive '%s' not recognized.\n"), file, linenum, key); return(1); } - } else if(strcmp(key, "Server") == 0 || strcmp(upperkey, "SERVER") == 0) { + } else if(strcmp(key, "Server") == 0) { /* let's attempt a replacement for the current repo */ char *server = strreplace(ptr, "$repo", section); @@ -720,7 +731,6 @@ static int _parseconfig(const char *file, const char *givensection, return(1); } } - free(upperkey); } } fclose(fp); @@ -753,7 +763,7 @@ int main(int argc, char *argv[]) { int ret = 0; struct sigaction new_action, old_action; -#if defined(HAVE_GETEUID) +#if defined(HAVE_GETEUID) && !defined(CYGWIN) /* geteuid undefined in CYGWIN */ uid_t myuid = geteuid(); #endif @@ -834,7 +844,7 @@ int main(int argc, char *argv[]) cleanup(ret); } -#if defined(HAVE_GETEUID) +#if defined(HAVE_GETEUID) && !defined(CYGWIN) /* check if we have sufficient permission for the requested operation */ if(myuid > 0 && needs_transaction()) { pm_printf(PM_LOG_ERROR, _("you cannot perform this operation unless you are root.\n")); @@ -867,9 +877,6 @@ int main(int argc, char *argv[]) /* start the requested operation */ switch(config->op) { - case PM_OP_ADD: - ret = pacman_add(pm_targets); - break; case PM_OP_REMOVE: ret = pacman_remove(pm_targets); break; diff --git a/src/pacman/pacman.h b/src/pacman/pacman.h index 9d23a89c..97d0301e 100644 --- a/src/pacman/pacman.h +++ b/src/pacman/pacman.h @@ -21,15 +21,14 @@ #include <alpm_list.h> -/* add.c, this should merge with upgrade.c */ -int pacman_add(alpm_list_t *targets); -int pacman_upgrade(alpm_list_t *targets); -/* sync.c */ -int pacman_sync(alpm_list_t *targets); /* query.c */ int pacman_query(alpm_list_t *targets); /* remove.c */ int pacman_remove(alpm_list_t *targets); +/* sync.c */ +int pacman_sync(alpm_list_t *targets); +/* upgrade.c */ +int pacman_upgrade(alpm_list_t *targets); /* deptest.c */ int pacman_deptest(alpm_list_t *targets); diff --git a/src/pacman/query.c b/src/pacman/query.c index e999a328..74d3ff21 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -1,7 +1,7 @@ /* * query.c * - * Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org> + * Copyright (c) 2002-2008 by Judd Vinet <jvinet@zeroflux.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 @@ -62,28 +62,28 @@ static int query_fileowner(alpm_list_t *targets) /* This code is here for safety only */ if(targets == NULL) { - fprintf(stderr, _("error: no file was specified for --owns\n")); + pm_fprintf(stderr, PM_LOG_ERROR, _("no file was specified for --owns\n")); return(1); } for(t = targets; t; t = alpm_list_next(t)) { int found = 0; char *filename = alpm_list_getdata(t); - char *bname; - char *dname; - char *rpath; + char *bname, *dname, *rpath; + const char *root; struct stat buf; alpm_list_t *i, *j; if(stat(filename, &buf) == -1) { - fprintf(stderr, _("error: failed to read file '%s': %s\n"), + pm_fprintf(stderr, PM_LOG_ERROR, _("failed to read file '%s': %s\n"), filename, strerror(errno)); ret++; continue; } if(S_ISDIR(buf.st_mode)) { - fprintf(stderr, _("error: cannot determine ownership of a directory\n")); + pm_fprintf(stderr, PM_LOG_ERROR, + _("cannot determine ownership of a directory\n")); ret++; continue; } @@ -94,20 +94,22 @@ static int query_fileowner(alpm_list_t *targets) free(dname); if(!rpath) { - fprintf(stderr, _("error: cannot determine real path for '%s': %s\n"), + pm_fprintf(stderr, PM_LOG_ERROR, _("cannot determine real path for '%s': %s\n"), filename, strerror(errno)); free(rpath); ret++; continue; } + root = alpm_option_get_root(); + for(i = alpm_db_getpkgcache(db_local); i && !found; i = alpm_list_next(i)) { pmpkg_t *info = alpm_list_getdata(i); for(j = alpm_pkg_get_files(info); j && !found; j = alpm_list_next(j)) { char path[PATH_MAX], *ppath, *pdname; snprintf(path, PATH_MAX, "%s%s", - alpm_option_get_root(), (const char *)alpm_list_getdata(j)); + root, (const char *)alpm_list_getdata(j)); /* avoid the costly resolve_path usage if the basenames don't match */ if(strcmp(mbasename(path), bname) != 0) { @@ -119,15 +121,20 @@ static int query_fileowner(alpm_list_t *targets) free(pdname); if(ppath && strcmp(ppath, rpath) == 0) { - printf(_("%s is owned by %s %s\n"), filename, - alpm_pkg_get_name(info), alpm_pkg_get_version(info)); + if (!config->quiet) { + printf(_("%s is owned by %s %s\n"), filename, + alpm_pkg_get_name(info), alpm_pkg_get_version(info)); + } else { + printf("%s %s\n", alpm_pkg_get_name(info), + alpm_pkg_get_version(info)); + } found = 1; } free(ppath); } } if(!found) { - fprintf(stderr, _("error: No package owns %s\n"), filename); + pm_fprintf(stderr, PM_LOG_ERROR, _("No package owns %s\n"), filename); ret++; } free(rpath); @@ -155,7 +162,6 @@ static int query_search(alpm_list_t *targets) } for(i = searchlist; i; i = alpm_list_next(i)) { - char *group = NULL; alpm_list_t *grp; pmpkg_t *pkg = alpm_list_getdata(i); @@ -176,8 +182,17 @@ static int query_search(alpm_list_t *targets) if (!config->quiet) { if((grp = alpm_pkg_get_groups(pkg)) != NULL) { - group = alpm_list_getdata(grp); - printf(" (%s)", (char *)alpm_list_getdata(grp)); + alpm_list_t *k; + printf(" ("); + for(k = grp; k; k = alpm_list_next(k)) { + const char *group = alpm_list_getdata(k); + printf("%s", group); + if(alpm_list_next(k)) { + /* only print a spacer if there are more groups */ + printf(" "); + } + } + printf(")"); } /* we need a newline and initial indent first */ @@ -197,33 +212,33 @@ static int query_search(alpm_list_t *targets) static int query_group(alpm_list_t *targets) { alpm_list_t *i, *j; - char *package = NULL; + char *grpname = NULL; int ret = 0; if(targets == NULL) { for(j = alpm_db_getgrpcache(db_local); j; j = alpm_list_next(j)) { pmgrp_t *grp = alpm_list_getdata(j); - const alpm_list_t *p, *pkgnames; + const alpm_list_t *p, *packages; const char *grpname; grpname = alpm_grp_get_name(grp); - pkgnames = alpm_grp_get_pkgs(grp); + packages = alpm_grp_get_pkgs(grp); - for(p = pkgnames; p; p = alpm_list_next(p)) { - printf("%s %s\n", grpname, (char *)alpm_list_getdata(p)); + for(p = packages; p; p = alpm_list_next(p)) { + printf("%s %s\n", grpname, alpm_pkg_get_name(alpm_list_getdata(p))); } } } else { for(i = targets; i; i = alpm_list_next(i)) { pmgrp_t *grp; - package = alpm_list_getdata(i); - grp = alpm_db_readgrp(db_local, package); + grpname = alpm_list_getdata(i); + grp = alpm_db_readgrp(db_local, grpname); if(grp) { - const alpm_list_t *p, *pkgnames = alpm_grp_get_pkgs(grp); - for(p = pkgnames; p; p = alpm_list_next(p)) { - printf("%s %s\n", package, (char *)alpm_list_getdata(p)); + const alpm_list_t *p, *packages = alpm_grp_get_pkgs(grp); + for(p = packages; p; p = alpm_list_next(p)) { + printf("%s %s\n", grpname, alpm_pkg_get_name(alpm_list_getdata(p))); } } else { - fprintf(stderr, _("error: group \"%s\" was not found\n"), package); + pm_fprintf(stderr, PM_LOG_ERROR, _("group \"%s\" was not found\n"), grpname); ret++; } } @@ -401,7 +416,7 @@ int pacman_query(alpm_list_t *targets) } if(pkg == NULL) { - fprintf(stderr, _("error: package \"%s\" not found\n"), strname); + pm_fprintf(stderr, PM_LOG_ERROR, _("package \"%s\" not found\n"), strname); ret++; continue; } diff --git a/src/pacman/remove.c b/src/pacman/remove.c index e3750e4c..4fe9bc81 100644 --- a/src/pacman/remove.c +++ b/src/pacman/remove.c @@ -29,24 +29,10 @@ /* pacman */ #include "pacman.h" #include "util.h" -#include "callback.h" #include "conf.h" extern pmdb_t *db_local; -/* Free the current transaction and print an error if unsuccessful */ -static int remove_cleanup(void) -{ - int ret = alpm_trans_release(); - if(ret != 0) { - pm_printf(PM_LOG_ERROR, _("failed to release transaction (%s)\n"), - alpm_strerrorlast()); - ret = 1; - } - - return(ret); -} - /** * @brief Remove a specified list of packages. * @@ -75,11 +61,11 @@ int pacman_remove(alpm_list_t *targets) printf(_(":: group %s:\n"), alpm_grp_get_name(grp)); list_display(" ", pkgnames); - all = yesno(_(" Remove whole content? [Y/n] ")); + all = yesno(1, _(" Remove whole content?")); for(p = pkgnames; p; p = alpm_list_next(p)) { char *pkg = alpm_list_getdata(p); - if(all || yesno(_(":: Remove %s from group %s? [Y/n] "), pkg, (char *)alpm_list_getdata(i))) { + if(all || yesno(1, _(":: Remove %s from group %s?"), pkg, (char *)alpm_list_getdata(i))) { finaltargs = alpm_list_add(finaltargs, strdup(pkg)); } } @@ -90,14 +76,7 @@ int pacman_remove(alpm_list_t *targets) } /* Step 1: create a new transaction */ - if(alpm_trans_init(PM_TRANS_TYPE_REMOVE, config->flags, - cb_trans_evt, cb_trans_conv, cb_trans_progress) == -1) { - fprintf(stderr, _("error: failed to init transaction (%s)\n"), - alpm_strerrorlast()); - if(pm_errno == PM_ERR_HANDLE_LOCK) { - printf(_(" if you're sure a package manager is not already\n" - " running, you can remove %s.\n"), alpm_option_get_lockfile()); - } + if(trans_init(PM_TRANS_TYPE_REMOVE, config->flags) == -1) { FREELIST(finaltargs); return(1); } @@ -107,9 +86,9 @@ int pacman_remove(alpm_list_t *targets) for(i = finaltargs; i; i = alpm_list_next(i)) { char *targ = alpm_list_getdata(i); if(alpm_trans_addtarget(targ) == -1) { - fprintf(stderr, _("error: '%s': %s\n"), + pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", targ, alpm_strerrorlast()); - remove_cleanup(); + trans_release(); FREELIST(finaltargs); return(1); } @@ -117,7 +96,7 @@ int pacman_remove(alpm_list_t *targets) /* Step 2: prepare the transaction based on its type, targets and flags */ if(alpm_trans_prepare(&data) == -1) { - fprintf(stderr, _("error: failed to prepare transaction (%s)\n"), + pm_fprintf(stderr, PM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), alpm_strerrorlast()); switch(pm_errno) { case PM_ERR_UNSATISFIED_DEPS: @@ -134,7 +113,7 @@ int pacman_remove(alpm_list_t *targets) default: break; } - remove_cleanup(); + trans_release(); FREELIST(finaltargs); return(1); } @@ -153,8 +132,8 @@ int pacman_remove(alpm_list_t *targets) list_display(_("Targets:"), lst); FREELIST(lst); /* get confirmation */ - if(yesno(_("\nDo you want to remove these packages? [Y/n] ")) == 0) { - remove_cleanup(); + if(yesno(1, _("\nDo you want to remove these packages?")) == 0) { + trans_release(); FREELIST(finaltargs); return(1); } @@ -163,15 +142,17 @@ int pacman_remove(alpm_list_t *targets) /* Step 3: actually perform the removal */ if(alpm_trans_commit(NULL) == -1) { - fprintf(stderr, _("error: failed to commit transaction (%s)\n"), + pm_fprintf(stderr, PM_LOG_ERROR, _("failed to commit transaction (%s)\n"), alpm_strerrorlast()); - remove_cleanup(); + trans_release(); FREELIST(finaltargs); return(1); } /* Step 4: release transaction resources */ - retval = remove_cleanup(); + if(trans_release() == -1) { + retval = 1; + } FREELIST(finaltargs); return(retval); } diff --git a/src/pacman/sync.c b/src/pacman/sync.c index e3e87703..134d4db3 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -29,15 +29,11 @@ #include <alpm.h> #include <alpm_list.h> -#include <download.h> /* downloadLastErrString */ -/* TODO remove above download.h inclusion once we abstract more, and also - * remove it from Makefile.am on the pacman side */ /* pacman */ #include "pacman.h" #include "util.h" #include "package.h" -#include "callback.h" #include "conf.h" extern pmdb_t *db_local; @@ -50,7 +46,7 @@ static int sync_cleandb(const char *dbpath, int keep_used) { dir = opendir(dbpath); if(dir == NULL) { - fprintf(stderr, _("error: could not access database directory\n")); + pm_fprintf(stderr, PM_LOG_ERROR, _("could not access database directory\n")); return(1); } @@ -61,7 +57,7 @@ static int sync_cleandb(const char *dbpath, int keep_used) { struct stat buf; alpm_list_t *syncdbs = NULL, *i; int found = 0; - char *dname = ent->d_name; + const char *dname = ent->d_name; if(!strcmp(dname, ".") || !strcmp(dname, "..")) { continue; @@ -72,7 +68,7 @@ static int sync_cleandb(const char *dbpath, int keep_used) { } /* build the full path */ - snprintf(path, PATH_MAX, "%s%s", dbpath, ent->d_name); + snprintf(path, PATH_MAX, "%s%s", dbpath, dname); /* skip entries that are not dirs (lock file, etc.) */ stat(path, &buf); if(!S_ISDIR(buf.st_mode)) { @@ -89,12 +85,13 @@ static int sync_cleandb(const char *dbpath, int keep_used) { /* We have a directory that doesn't match any syncdb. * Ask the user if he wants to remove it. */ if(!found) { - if(!yesno(_("Do you want to remove %s? [Y/n] "), path)) { + if(!yesno(1, _("Do you want to remove %s?"), path)) { continue; } if(rmrf(path)) { - fprintf(stderr, _("error: could not remove repository directory\n")); + pm_fprintf(stderr, PM_LOG_ERROR, + _("could not remove repository directory\n")); return(1); } } @@ -108,7 +105,7 @@ static int sync_cleandb_all(void) { char newdbpath[PATH_MAX]; printf(_("Database directory: %s\n"), dbpath); - if(!yesno(_("Do you want to remove unused repositories? [Y/n] "))) { + if(!yesno(1, _("Do you want to remove unused repositories?"))) { return(0); } /* The sync dbs were previously put in dbpath/, but are now in dbpath/sync/, @@ -133,19 +130,29 @@ static int sync_cleancache(int level) /* incomplete cleanup */ DIR *dir; struct dirent *ent; - /* Let's vastly improve the way this is done. Before, we went by package - * name. Instead, let's only keep packages we have installed. Open up each - * package and see if it has an entry in the local DB; if not, delete it. - */ + /* Open up each package and see if it should be deleted, + * depending on the clean method used */ printf(_("Cache directory: %s\n"), cachedir); - if(!yesno(_("Do you want to remove uninstalled packages from cache? [Y/n] "))) { - return(0); + switch(config->cleanmethod) { + case PM_CLEAN_KEEPINST: + if(!yesno(1, _("Do you want to remove uninstalled packages from cache?"))) { + return(0); + } + break; + case PM_CLEAN_KEEPCUR: + if(!yesno(1, _("Do you want to remove outdated packages from cache?"))) { + return(0); + } + break; + default: + /* this should not happen : the config parsing doesn't set any other value */ + return(1); } printf(_("removing old packages from cache... ")); dir = opendir(cachedir); if(dir == NULL) { - fprintf(stderr, _("error: could not access cache directory\n")); + pm_fprintf(stderr, PM_LOG_ERROR, _("could not access cache directory\n")); return(1); } @@ -153,13 +160,16 @@ static int sync_cleancache(int level) /* step through the directory one file at a time */ while((ent = readdir(dir)) != NULL) { char path[PATH_MAX]; - pmpkg_t *localpkg = NULL, *dbpkg = NULL; + int delete = 1; + pmpkg_t *localpkg = NULL, *pkg = NULL; + alpm_list_t *sync_dbs = alpm_option_get_syncdbs(); + alpm_list_t *j; if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) { continue; } /* build the full filepath */ - snprintf(path, PATH_MAX, "%s/%s", cachedir, ent->d_name); + snprintf(path, PATH_MAX, "%s%s", cachedir, ent->d_name); /* attempt to load the package, skip file on failures as we may have * files here that aren't valid packages. we also don't need a full @@ -167,36 +177,56 @@ static int sync_cleancache(int level) if(alpm_pkg_load(path, 0, &localpkg) != 0 || localpkg == NULL) { continue; } - /* check if this package is in the local DB */ - dbpkg = alpm_db_get_pkg(db_local, alpm_pkg_get_name(localpkg)); - if(dbpkg == NULL) { - /* delete package, not present in local DB */ - unlink(path); - } else if(alpm_pkg_vercmp(alpm_pkg_get_version(localpkg), - alpm_pkg_get_version(dbpkg)) != 0) { - /* delete package, it was found but version differs */ - unlink(path); + switch(config->cleanmethod) { + case PM_CLEAN_KEEPINST: + /* check if this package is in the local DB */ + pkg = alpm_db_get_pkg(db_local, alpm_pkg_get_name(localpkg)); + if(pkg != NULL && alpm_pkg_vercmp(alpm_pkg_get_version(localpkg), + alpm_pkg_get_version(pkg)) == 0) { + /* package was found in local DB and version matches, keep it */ + delete = 0; + } + break; + case PM_CLEAN_KEEPCUR: + /* check if this package is in a sync DB */ + for(j = sync_dbs; j && delete; j = alpm_list_next(j)) { + pmdb_t *db = alpm_list_getdata(j); + pkg = alpm_db_get_pkg(db, alpm_pkg_get_name(localpkg)); + if(pkg != NULL && alpm_pkg_vercmp(alpm_pkg_get_version(localpkg), + alpm_pkg_get_version(pkg)) == 0) { + /* package was found in a sync DB and version matches, keep it */ + delete = 0; + } + } + break; + default: + /* this should not happen : the config parsing doesn't set any other value */ + delete = 0; + break; } - /* else version was the same, so keep the package */ /* free the local file package */ alpm_pkg_free(localpkg); + + if(delete) { + unlink(path); + } } printf(_("done.\n")); } else { /* full cleanup */ printf(_("Cache directory: %s\n"), cachedir); - if(!yesno(_("Do you want to remove ALL packages from cache? [Y/n] "))) { + if(!yesno(0, _("Do you want to remove ALL packages from cache?"))) { return(0); } printf(_("removing all packages from cache... ")); if(rmrf(cachedir)) { - fprintf(stderr, _("error: could not remove cache directory\n")); + pm_fprintf(stderr, PM_LOG_ERROR, _("could not remove cache directory\n")); return(1); } if(makepath(cachedir)) { - fprintf(stderr, _("error: could not create new cache directory\n")); + pm_fprintf(stderr, PM_LOG_ERROR, _("could not create new cache directory\n")); return(1); } printf(_("done.\n")); @@ -205,52 +235,22 @@ static int sync_cleancache(int level) return(0); } -static int sync_trans_init(pmtransflag_t flags) { - if(alpm_trans_init(PM_TRANS_TYPE_SYNC, flags, cb_trans_evt, - cb_trans_conv, cb_trans_progress) == -1) { - fprintf(stderr, _("error: failed to init transaction (%s)\n"), - alpm_strerrorlast()); - if(pm_errno == PM_ERR_HANDLE_LOCK) { - printf(_(" if you're sure a package manager is not already\n" - " running, you can remove %s.\n"), alpm_option_get_lockfile()); - } - return(-1); - } - return(0); -} - -static int sync_trans_release() { - if(alpm_trans_release() == -1) { - fprintf(stderr, _("error: failed to release transaction (%s)\n"), - alpm_strerrorlast()); - return(-1); - } - return(0); -} static int sync_synctree(int level, alpm_list_t *syncs) { alpm_list_t *i; int success = 0, ret; + if(trans_init(PM_TRANS_TYPE_SYNC, 0) == -1) { + return(0); + } + for(i = syncs; i; i = alpm_list_next(i)) { pmdb_t *db = alpm_list_getdata(i); ret = alpm_db_update((level < 2 ? 0 : 1), db); if(ret < 0) { - if(pm_errno == PM_ERR_DB_SYNC) { - /* use libdownload error */ - /* TODO breaking abstraction barrier here? - * pacman -> libalpm -> libdownload - * - * Yes. This will be here until we add a nice pacman "pm_errstr" or - * something, OR add all libdownload error codes into the pm_error enum - */ - fprintf(stderr, _("error: failed to synchronize %s: %s\n"), - alpm_db_get_name(db), downloadLastErrString); - } else { - fprintf(stderr, _("error: failed to update %s (%s)\n"), - alpm_db_get_name(db), alpm_strerrorlast()); - } + pm_fprintf(stderr, PM_LOG_ERROR, _("failed to update %s (%s)\n"), + alpm_db_get_name(db), alpm_strerrorlast()); } else if(ret == 1) { printf(_(" %s is up to date\n"), alpm_db_get_name(db)); success++; @@ -259,10 +259,16 @@ static int sync_synctree(int level, alpm_list_t *syncs) } } + if(trans_release() == -1) { + return(0); + } /* We should always succeed if at least one DB was upgraded - we may possibly * fail later with unresolved deps, but that should be rare, and would be * expected */ + if(!success) { + pm_fprintf(stderr, PM_LOG_ERROR, _("failed to synchronize any databases\n")); + } return(success > 0); } @@ -289,8 +295,6 @@ static int sync_search(alpm_list_t *syncs, alpm_list_t *targets) found = 1; } for(j = ret; j; j = alpm_list_next(j)) { - /* print repo/name (group) info about each package in our list */ - char *group = NULL; alpm_list_t *grp; pmpkg_t *pkg = alpm_list_getdata(j); @@ -311,8 +315,17 @@ static int sync_search(alpm_list_t *syncs, alpm_list_t *targets) if (!config->quiet) { if((grp = alpm_pkg_get_groups(pkg)) != NULL) { - group = alpm_list_getdata(grp); - printf(" (%s)", (char *)alpm_list_getdata(grp)); + alpm_list_t *k; + printf(" ("); + for(k = grp; k; k = alpm_list_next(k)) { + const char *group = alpm_list_getdata(k); + printf("%s", group); + if(alpm_list_next(k)) { + /* only print a spacer if there are more groups */ + printf(" "); + } + } + printf(")"); } /* we need a newline and initial indent first */ @@ -332,7 +345,8 @@ static int sync_search(alpm_list_t *syncs, alpm_list_t *targets) static int sync_group(int level, alpm_list_t *syncs, alpm_list_t *targets) { - alpm_list_t *i, *j; + alpm_list_t *i, *j, *k; + alpm_list_t *pkgnames = NULL; if(targets) { for(i = targets; i; i = alpm_list_next(i)) { @@ -342,9 +356,14 @@ static int sync_group(int level, alpm_list_t *syncs, alpm_list_t *targets) pmgrp_t *grp = alpm_db_readgrp(db, grpname); if(grp) { - /* TODO this should be a lot cleaner, why two outputs? */ printf("%s\n", (char *)alpm_grp_get_name(grp)); - list_display(" ", alpm_grp_get_pkgs(grp)); + /* get names of packages in group */ + for(k = alpm_grp_get_pkgs(grp); k; k = alpm_list_next(k)) { + pkgnames = alpm_list_add(pkgnames, + (char*)alpm_pkg_get_name(k->data)); + } + list_display(" ", pkgnames); + alpm_list_free(pkgnames); } } } @@ -357,7 +376,12 @@ static int sync_group(int level, alpm_list_t *syncs, alpm_list_t *targets) printf("%s\n", (char *)alpm_grp_get_name(grp)); if(grp && level > 1) { - list_display(" ", alpm_grp_get_pkgs(grp)); + for(k = alpm_grp_get_pkgs(grp); k; k = alpm_list_next(k)) { + pkgnames = alpm_list_add(pkgnames, + (char*)alpm_pkg_get_name(k->data)); + } + list_display(" ", pkgnames); + alpm_list_free(pkgnames); } } } @@ -395,7 +419,8 @@ static int sync_info(alpm_list_t *syncs, alpm_list_t *targets) } if(!db) { - fprintf(stderr, _("error: repository '%s' does not exist\n"), repo); + pm_fprintf(stderr, PM_LOG_ERROR, + _("repository '%s' does not exist\n"), repo); return(1); } @@ -410,7 +435,8 @@ static int sync_info(alpm_list_t *syncs, alpm_list_t *targets) } if(!foundpkg) { - fprintf(stderr, _("error: package '%s' was not found in repository '%s'\n"), pkgstr, repo); + pm_fprintf(stderr, PM_LOG_ERROR, + _("package '%s' was not found in repository '%s'\n"), pkgstr, repo); ret++; } } else { @@ -430,7 +456,8 @@ static int sync_info(alpm_list_t *syncs, alpm_list_t *targets) } } if(!foundpkg) { - fprintf(stderr, _("error: package '%s' was not found\n"), pkgstr); + pm_fprintf(stderr, PM_LOG_ERROR, + _("package '%s' was not found\n"), pkgstr); ret++; } } @@ -467,7 +494,8 @@ static int sync_list(alpm_list_t *syncs, alpm_list_t *targets) } if(db == NULL) { - fprintf(stderr, _("error: repository \"%s\" was not found.\n"),repo); + pm_fprintf(stderr, PM_LOG_ERROR, + _("repository \"%s\" was not found.\n"),repo); alpm_list_free(ls); return(1); } @@ -499,74 +527,43 @@ static int sync_list(alpm_list_t *syncs, alpm_list_t *targets) return(0); } -static int sync_trans(alpm_list_t *targets, int sync_only) +static alpm_list_t *syncfirst() { + alpm_list_t *i, *res = NULL; + + for(i = config->syncfirst; i; i = alpm_list_next(i)) { + char *pkgname = alpm_list_getdata(i); + pmpkg_t *pkg = alpm_db_get_pkg(alpm_option_get_localdb(), pkgname); + if(pkg == NULL) { + continue; + } + + if(alpm_sync_newversion(pkg, alpm_option_get_syncdbs())) { + res = alpm_list_add(res, strdup(pkgname)); + } + } + + return(res); +} + +static int sync_trans(alpm_list_t *targets) { int retval = 0; alpm_list_t *data = NULL; alpm_list_t *sync_dbs = alpm_option_get_syncdbs(); /* Step 1: create a new transaction... */ - if(sync_trans_init(config->flags) == -1) { + if(trans_init(PM_TRANS_TYPE_SYNC, config->flags) == -1) { return(1); } - if(config->op_s_sync) { - /* grab a fresh package list */ - printf(_(":: Synchronizing package databases...\n")); - alpm_logaction("synchronizing package lists\n"); - if(!sync_synctree(config->op_s_sync, sync_dbs)) { - fprintf(stderr, _("error: failed to synchronize any databases\n")); - retval = 1; - goto cleanup; - } - if(sync_only) { - goto cleanup; - } - } - if(config->op_s_upgrade) { - alpm_list_t *pkgs, *i; - printf(_(":: Starting full system upgrade...\n")); alpm_logaction("starting full system upgrade\n"); if(alpm_trans_sysupgrade() == -1) { - fprintf(stderr, _("error: %s\n"), alpm_strerrorlast()); + pm_fprintf(stderr, PM_LOG_ERROR, "%s\n", alpm_strerrorlast()); retval = 1; goto cleanup; } - - if(!(alpm_trans_get_flags() & (PM_TRANS_FLAG_DOWNLOADONLY | PM_TRANS_FLAG_PRINTURIS))) { - /* check if pacman itself is one of the packages to upgrade. - * this can prevent some of the "syntax error" problems users can have - * when sysupgrade'ing with an older version of pacman. - */ - pkgs = alpm_trans_get_pkgs(); - for(i = pkgs; i; i = alpm_list_next(i)) { - pmsyncpkg_t *sync = alpm_list_getdata(i); - pmpkg_t *spkg = alpm_sync_get_pkg(sync); - /* TODO pacman name should probably not be hardcoded. In addition, we - * have problems on an -Syu if pacman has to pull in deps, so recommend - * an '-S pacman' operation */ - if(strcmp("pacman", alpm_pkg_get_name(spkg)) == 0) { - printf("\n"); - printf(_(":: pacman has detected a newer version of itself.\n")); - if(yesno(_(":: Do you want to cancel the current operation\n" - ":: and install the new pacman version now? [Y/n] "))) { - if(sync_trans_release() == -1) { - return(1); - } - if(sync_trans_init(0) == -1) { - return(1); - } - if(alpm_trans_addtarget("pacman") == -1) { - fprintf(stderr, _("error: pacman: %s\n"), alpm_strerrorlast()); - return(1); - } - break; - } - } - } - } } else { alpm_list_t *i; @@ -583,7 +580,7 @@ static int sync_trans(alpm_list_t *targets, int sync_only) continue; } if(pm_errno != PM_ERR_PKG_NOT_FOUND) { - fprintf(stderr, _("error: '%s': %s\n"), + pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", targ, alpm_strerrorlast()); retval = 1; goto cleanup; @@ -594,26 +591,31 @@ static int sync_trans(alpm_list_t *targets, int sync_only) pmdb_t *db = alpm_list_getdata(j); grp = alpm_db_readgrp(db, targ); if(grp) { - alpm_list_t *k; + alpm_list_t *k, *pkgnames = NULL; found++; printf(_(":: group %s (including ignored packages):\n"), targ); /* remove dupe entries in case a package exists in multiple repos */ - const alpm_list_t *grppkgs = alpm_grp_get_pkgs(grp); + alpm_list_t *grppkgs = alpm_grp_get_pkgs(grp); alpm_list_t *pkgs = alpm_list_remove_dupes(grppkgs); - list_display(" ", pkgs); - if(yesno(_(":: Install whole content? [Y/n] "))) { - for(k = pkgs; k; k = alpm_list_next(k)) { + for(k = pkgs; k; k = alpm_list_next(k)) { + pkgnames = alpm_list_add(pkgnames, + (char*)alpm_pkg_get_name(k->data)); + } + list_display(" ", pkgnames); + if(yesno(1, _(":: Install whole content?"))) { + for(k = pkgnames; k; k = alpm_list_next(k)) { targets = alpm_list_add(targets, strdup(alpm_list_getdata(k))); } } else { - for(k = pkgs; k; k = alpm_list_next(k)) { + for(k = pkgnames; k; k = alpm_list_next(k)) { char *pkgname = alpm_list_getdata(k); - if(yesno(_(":: Install %s from group %s? [Y/n] "), pkgname, targ)) { + if(yesno(1, _(":: Install %s from group %s?"), pkgname, targ)) { targets = alpm_list_add(targets, strdup(pkgname)); } } } + alpm_list_free(pkgnames); alpm_list_free(pkgs); } } @@ -622,7 +624,9 @@ static int sync_trans(alpm_list_t *targets, int sync_only) alpm_list_t *prov = NULL; for(j = sync_dbs; j; j = alpm_list_next(j)) { pmdb_t *db = alpm_list_getdata(j); - prov = alpm_list_join(prov, alpm_db_whatprovides(db, targ)); + alpm_list_t *dblist = alpm_db_getpkgcache(db); + alpm_list_t *satisfiers = alpm_find_pkg_satisfiers(dblist, targ); + prov = alpm_list_join(prov, satisfiers); } if(prov != NULL) { if(alpm_list_count(prov) == 1) { @@ -634,7 +638,8 @@ static int sync_trans(alpm_list_t *targets, int sync_only) targets = alpm_list_add(targets, strdup(pname)); } else { alpm_list_t *k; - fprintf(stderr, _("error: several packages provide %s, please specify one :\n"), targ); + pm_fprintf(stderr, PM_LOG_ERROR, + _("several packages provide %s, please specify one :\n"), targ); for(k = prov; k; k = alpm_list_next(k)) { pmpkg_t *pkg = alpm_list_getdata(k); printf("%s ", alpm_pkg_get_name(pkg)); @@ -645,7 +650,8 @@ static int sync_trans(alpm_list_t *targets, int sync_only) goto cleanup; } } else { - fprintf(stderr, _("error: '%s': not found in sync db\n"), targ); + pm_fprintf(stderr, PM_LOG_ERROR, + _("'%s': not found in sync db\n"), targ); retval = 1; goto cleanup; } @@ -656,7 +662,7 @@ static int sync_trans(alpm_list_t *targets, int sync_only) /* Step 2: "compute" the transaction based on targets and flags */ if(alpm_trans_prepare(&data) == -1) { - fprintf(stderr, _("error: failed to prepare transaction (%s)\n"), + pm_fprintf(stderr, PM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), alpm_strerrorlast()); switch(pm_errno) { alpm_list_t *i; @@ -698,19 +704,9 @@ static int sync_trans(alpm_list_t *targets, int sync_only) printf("\n"); if(config->op_s_downloadonly) { - if(config->noconfirm) { - printf(_("Beginning download...\n")); - confirm = 1; - } else { - confirm = yesno(_("Proceed with download? [Y/n] ")); - } + confirm = yesno(1, _("Proceed with download?")); } else { - if(config->noconfirm) { - printf(_("Beginning upgrade process...\n")); - confirm = 1; - } else { - confirm = yesno(_("Proceed with installation? [Y/n] ")); - } + confirm = yesno(1, _("Proceed with installation?")); } if(!confirm) { goto cleanup; @@ -719,7 +715,7 @@ static int sync_trans(alpm_list_t *targets, int sync_only) /* Step 3: actually perform the installation */ if(alpm_trans_commit(&data) == -1) { - fprintf(stderr, _("error: failed to commit transaction (%s)\n"), + pm_fprintf(stderr, PM_LOG_ERROR, _("failed to commit transaction (%s)\n"), alpm_strerrorlast()); switch(pm_errno) { alpm_list_t *i; @@ -741,9 +737,11 @@ static int sync_trans(alpm_list_t *targets, int sync_only) } } break; - case PM_ERR_PKG_CORRUPTED: + case PM_ERR_PKG_INVALID: + case PM_ERR_DLT_INVALID: for(i = data; i; i = alpm_list_next(i)) { - printf("%s", (char*)alpm_list_getdata(i)); + char *filename = alpm_list_getdata(i); + printf(_("%s is invalid or corrupted\n"), filename); } break; default: @@ -760,7 +758,7 @@ cleanup: if(data) { FREELIST(data); } - if(sync_trans_release() == -1) { + if(trans_release() == -1) { retval = 1; } @@ -770,20 +768,19 @@ cleanup: int pacman_sync(alpm_list_t *targets) { alpm_list_t *sync_dbs = NULL; - int sync_only = 0; /* clean the cache */ if(config->op_s_clean) { int ret = 0; - if(sync_trans_init(0) == -1) { + if(trans_init(PM_TRANS_TYPE_SYNC, 0) == -1) { return(1); } ret += sync_cleancache(config->op_s_clean); ret += sync_cleandb_all(); - if(sync_trans_release() == -1) { + if(trans_release() == -1) { ret++; } @@ -797,18 +794,49 @@ int pacman_sync(alpm_list_t *targets) return(1); } - if(config->op_s_search || config->group - || config->op_s_info || config->op_q_list) { - sync_only = 1; - } else if(targets == NULL && !(config->op_s_sync || config->op_s_upgrade)) { + if(targets == NULL && !(config->op_s_sync || config->op_s_upgrade + || config->op_s_search || config->group + || config->op_s_info || config->op_q_list)) { /* don't proceed here unless we have an operation that doesn't require * a target list */ pm_printf(PM_LOG_ERROR, _("no targets specified (use -h for help)\n")); return(1); } + if(config->op_s_sync) { + /* grab a fresh package list */ + printf(_(":: Synchronizing package databases...\n")); + alpm_logaction("synchronizing package lists\n"); + if(!sync_synctree(config->op_s_sync, sync_dbs)) { + return(1); + } + config->op_s_sync = 0; + } + if(needs_transaction()) { - if(sync_trans(targets, sync_only) == 1) { + alpm_list_t *targs = alpm_list_strdup(targets); + if(!(config->flags & (PM_TRANS_FLAG_DOWNLOADONLY | PM_TRANS_FLAG_PRINTURIS))) { + /* check for newer versions of packages to be upgraded first */ + alpm_list_t *packages = syncfirst(); + if(packages) { + printf(_(":: The following packages should be upgraded first :\n")); + list_display(" ", packages); + if(yesno(1, _(":: Do you want to cancel the current operation\n" + ":: and upgrade these packages now?"))) { + FREELIST(targs); + targs = packages; + config->flags = 0; + config->op_s_upgrade = 0; + } else { + FREELIST(packages); + } + printf("\n"); + } + } + + int ret = sync_trans(targs); + FREELIST(targs); + if(ret == 1) { return(1); } } diff --git a/src/pacman/add.c b/src/pacman/upgrade.c index fd40f005..c54b3ed7 100644 --- a/src/pacman/add.c +++ b/src/pacman/upgrade.c @@ -1,5 +1,5 @@ /* - * add.c + * upgrade.c * * Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org> * @@ -28,23 +28,9 @@ /* pacman */ #include "pacman.h" -#include "callback.h" #include "conf.h" #include "util.h" -/* Free the current transaction and print an error if unsuccessful */ -static int add_cleanup(void) -{ - int ret = alpm_trans_release(); - if(ret != 0) { - pm_printf(PM_LOG_ERROR, _("failed to release transaction (%s)\n"), - alpm_strerrorlast()); - ret = 1; - } - - return(ret); -} - /** * @brief Upgrade a specified list of packages. * @@ -54,23 +40,8 @@ static int add_cleanup(void) */ int pacman_upgrade(alpm_list_t *targets) { - /* this is basically just a remove-then-add process. pacman_add() will */ - /* handle it */ - config->upgrade = 1; - return(pacman_add(targets)); -} - -/** - * @brief Add a specified list of packages which cannot already be installed. - * - * @param targets a list of packages (as strings) to add - * - * @return 0 on success, 1 on failure - */ -int pacman_add(alpm_list_t *targets) -{ alpm_list_t *i, *data = NULL; - pmtranstype_t transtype = PM_TRANS_TYPE_ADD; + pmtranstype_t transtype = PM_TRANS_TYPE_UPGRADE; int retval = 0; if(targets == NULL) { @@ -93,20 +64,7 @@ int pacman_add(alpm_list_t *targets) } /* Step 1: create a new transaction */ - if(config->upgrade == 1) { - /* if upgrade flag was set, change this to an upgrade transaction */ - transtype = PM_TRANS_TYPE_UPGRADE; - } - - if(alpm_trans_init(transtype, config->flags, cb_trans_evt, - cb_trans_conv, cb_trans_progress) == -1) { - /* TODO: error messages should be in the front end, not the back */ - fprintf(stderr, _("error: %s\n"), alpm_strerrorlast()); - if(pm_errno == PM_ERR_HANDLE_LOCK) { - /* TODO this and the 2 other places should probably be on stderr */ - printf(_(" if you're sure a package manager is not already\n" - " running, you can remove %s.\n"), alpm_option_get_lockfile()); - } + if(trans_init(transtype, config->flags) == -1) { return(1); } @@ -115,9 +73,9 @@ int pacman_add(alpm_list_t *targets) for(i = targets; i; i = alpm_list_next(i)) { char *targ = alpm_list_getdata(i); if(alpm_trans_addtarget(targ) == -1) { - fprintf(stderr, _("error: '%s': %s\n"), + pm_fprintf(stderr, PM_LOG_ERROR, "'%s': %s\n", targ, alpm_strerrorlast()); - add_cleanup(); + trans_release(); return(1); } } @@ -125,7 +83,7 @@ int pacman_add(alpm_list_t *targets) /* Step 2: "compute" the transaction based on targets and flags */ /* TODO: No, compute nothing. This is stupid. */ if(alpm_trans_prepare(&data) == -1) { - fprintf(stderr, _("error: failed to prepare transaction (%s)\n"), + pm_fprintf(stderr, PM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), alpm_strerrorlast()); switch(pm_errno) { case PM_ERR_UNSATISFIED_DEPS: @@ -171,7 +129,7 @@ int pacman_add(alpm_list_t *targets) default: break; } - add_cleanup(); + trans_release(); FREELIST(data); return(1); } @@ -179,12 +137,15 @@ int pacman_add(alpm_list_t *targets) /* Step 3: perform the installation */ if(alpm_trans_commit(NULL) == -1) { - fprintf(stderr, _("error: failed to commit transaction (%s)\n"), alpm_strerrorlast()); - add_cleanup(); + pm_fprintf(stderr, PM_LOG_ERROR, _("failed to commit transaction (%s)\n"), + alpm_strerrorlast()); + trans_release(); return(1); } - retval = add_cleanup(); + if(trans_release() == -1) { + retval = 1; + } return(retval); } diff --git a/src/pacman/util.c b/src/pacman/util.c index 0facfdd1..2e4ee86e 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -42,6 +42,33 @@ /* pacman */ #include "util.h" #include "conf.h" +#include "callback.h" + + +int trans_init(pmtranstype_t type, pmtransflag_t flags) +{ + if(alpm_trans_init(type, flags, cb_trans_evt, + cb_trans_conv, cb_trans_progress) == -1) { + pm_fprintf(stderr, PM_LOG_ERROR, _("failed to init transaction (%s)\n"), + alpm_strerrorlast()); + if(pm_errno == PM_ERR_HANDLE_LOCK) { + fprintf(stderr, _(" if you're sure a package manager is not already\n" + " running, you can remove %s\n"), alpm_option_get_lockfile()); + } + return(-1); + } + return(0); +} + +int trans_release() +{ + if(alpm_trans_release() == -1) { + pm_fprintf(stderr, PM_LOG_ERROR, _("failed to release transaction (%s)\n"), + alpm_strerrorlast()); + return(-1); + } + return(0); +} int needs_transaction() { @@ -94,33 +121,38 @@ int getcols() /* does the same thing as 'mkdir -p' */ int makepath(const char *path) { - char *orig, *str, *ptr; - char full[PATH_MAX+1] = ""; - mode_t oldmask; - - oldmask = umask(0000); + /* A bit of pointer hell here. Descriptions: + * orig - a copy of path so we can safely butcher it with strsep + * str - the current position in the path string (after the delimiter) + * ptr - the original position of str after calling strsep + * incr - incrementally generated path for use in stat/mkdir call + */ + char *orig, *str, *ptr, *incr; + mode_t oldmask = umask(0000); + int ret = 0; orig = strdup(path); + incr = calloc(strlen(orig) + 1, sizeof(char)); str = orig; while((ptr = strsep(&str, "/"))) { if(strlen(ptr)) { struct stat buf; - - /* TODO we should use strncat */ - strcat(full, "/"); - strcat(full, ptr); - if(stat(full, &buf)) { - if(mkdir(full, 0755)) { - free(orig); - umask(oldmask); - return(1); + /* we have another path component- append the newest component to + * existing string and create one more level of dir structure */ + strcat(incr, "/"); + strcat(incr, ptr); + if(stat(incr, &buf)) { + if(mkdir(incr, 0755)) { + ret = 1; + break; } } } } free(orig); + free(incr); umask(oldmask); - return(0); + return(ret); } /* does the same thing as 'rm -rf' */ @@ -234,6 +266,10 @@ void indentprint(const char *str, int indent) p = wcstr; cidx = indent; + if(!p) { + return; + } + while(*p) { if(*p == L' ') { const wchar_t *q, *next; @@ -464,25 +500,22 @@ void display_targets(const alpm_list_t *syncpkgs, pmdb_t *db_local) pmsyncpkg_t *sync = alpm_list_getdata(i); pmpkg_t *pkg = alpm_sync_get_pkg(sync); - /* If this sync record is a replacement, the data member contains - * a list of packages to be removed due to the package that is being - * installed. */ - if(alpm_sync_get_type(sync) == PM_SYNC_TYPE_REPLACE) { - alpm_list_t *to_replace = alpm_sync_get_data(sync); + /* The removes member contains a list of packages to be removed + * due to the package that is being installed. */ + alpm_list_t *to_replace = alpm_sync_get_removes(sync); - for(j = to_replace; j; j = alpm_list_next(j)) { - pmpkg_t *rp = alpm_list_getdata(j); - const char *name = alpm_pkg_get_name(rp); + for(j = to_replace; j; j = alpm_list_next(j)) { + pmpkg_t *rp = alpm_list_getdata(j); + const char *name = alpm_pkg_get_name(rp); - if(!alpm_list_find_str(to_remove, name)) { - rsize += alpm_pkg_get_isize(rp); - to_remove = alpm_list_add(to_remove, strdup(name)); - } + if(!alpm_list_find_str(to_remove, name)) { + rsize += alpm_pkg_get_isize(rp); + to_remove = alpm_list_add(to_remove, strdup(name)); } } dispsize = alpm_pkg_get_size(pkg); - dlsize += alpm_pkg_download_size(pkg, db_local); + dlsize += alpm_pkg_download_size(pkg); isize += alpm_pkg_get_isize(pkg); /* print the package size with the output if ShowSize option set */ @@ -520,38 +553,50 @@ void display_targets(const alpm_list_t *syncpkgs, pmdb_t *db_local) printf("\n"); printf(_("Total Download Size: %.2f MB\n"), mbdlsize); - - /* TODO because all pkgs don't include isize, this is a crude hack */ - if(mbisize > mbdlsize) { - printf(_("Total Installed Size: %.2f MB\n"), mbisize); - } + printf(_("Total Installed Size: %.2f MB\n"), mbisize); FREELIST(targets); } /* presents a prompt and gets a Y/N answer */ -/* TODO there must be a better way */ -int yesno(char *fmt, ...) +int yesno(short preset, char *fmt, ...) { char response[32]; va_list args; + FILE *stream; if(config->noconfirm) { - return(1); + stream = stdout; + } else { + /* Use stderr so questions are always displayed when redirecting output */ + stream = stderr; } va_start(args, fmt); - /* Use stderr so questions are always displayed when redirecting output */ - vfprintf(stderr, fmt, args); + vfprintf(stream, fmt, args); va_end(args); + if(preset) { + fprintf(stream, " %s ", _("[Y/n]")); + } else { + fprintf(stream, " %s ", _("[y/N]")); + } + + if(config->noconfirm) { + fprintf(stream, "\n"); + return(preset); + } + if(fgets(response, 32, stdin)) { - if(strlen(response) != 0) { - strtrim(response); + strtrim(response); + if(strlen(response) == 0) { + return(preset); } - if(!strcasecmp(response, _("Y")) || !strcasecmp(response, _("YES")) || strlen(response) == 0) { + if(!strcasecmp(response, _("Y")) || !strcasecmp(response, _("YES"))) { return(1); + } else if (!strcasecmp(response, _("N")) || !strcasecmp(response, _("NO"))) { + return(0); } } return(0); diff --git a/src/pacman/util.h b/src/pacman/util.h index 0273512e..722e4ab6 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -36,6 +36,8 @@ /* update speed for the fill_progress based functions */ #define UPDATE_SPEED_SEC 0.2f +int trans_init(pmtranstype_t type, pmtransflag_t flags); +int trans_release(); int needs_transaction(); int getcols(); int makepath(const char *path); @@ -50,7 +52,7 @@ alpm_list_t *strsplit(const char *str, const char splitchar); void string_display(const char *title, const char *string); void list_display(const char *title, const alpm_list_t *list); void display_targets(const alpm_list_t *syncpkgs, pmdb_t *db_local); -int yesno(char *fmt, ...); +int yesno(short preset, char *fmt, ...); int pm_printf(pmloglevel_t level, const char *format, ...) __attribute__((format(printf,2,3))); int pm_fprintf(FILE *stream, pmloglevel_t level, const char *format, ...) __attribute__((format(printf,3,4))); int pm_vfprintf(FILE *stream, pmloglevel_t level, const char *format, va_list args) __attribute__((format(printf,3,0))); diff --git a/src/util/testdb.c b/src/util/testdb.c index 122a3fb5..f354ecab 100644 --- a/src/util/testdb.c +++ b/src/util/testdb.c @@ -147,6 +147,14 @@ int main(int argc, char **argv) free(depstring); } + /* check conflicts */ + data = alpm_checkdbconflicts(db); + for(i = data; i; i = i->next) { + pmconflict_t *conflict = alpm_list_getdata(i); + printf("%s conflicts with %s\n", alpm_conflict_get_package1(conflict), + alpm_conflict_get_package2(conflict)); + } + cleanup(retval); } diff --git a/src/util/testpkg.c b/src/util/testpkg.c index 64056ce4..6e8f9d1c 100644 --- a/src/util/testpkg.c +++ b/src/util/testpkg.c @@ -63,7 +63,7 @@ int main(int argc, char **argv) case PM_ERR_PKG_OPEN: printf("Cannot open the given file.\n"); break; - case PM_ERR_LIBARCHIVE_ERROR: + case PM_ERR_LIBARCHIVE: case PM_ERR_PKG_INVALID: printf("Package is invalid.\n"); break; |