diff options
175 files changed, 6142 insertions, 3743 deletions
@@ -90,6 +90,17 @@ alpm_list_t *alpm_list_add(alpm_list_t *list, void *data) NOT if(!strcmp(a, b)) +8. Use spaces around almost all arithmetic, comparison and assignment + operators and after all ',;:' separators. + + foobar[2 * size + 1] = function(a, 6); + NOT + foobar[2*size+1]=function(a,6); + + for(a = 0; a < n && n > 0; a++,n--) {} + NOT + for(a=0;a<n&&n>0;a++,n--) {} + Other Concerns -------------- @@ -103,8 +114,6 @@ general pattern, including blank lines: [source,C] ------------------------------------------- -#include "config.h" - #include <standardheader.h> #include <another.h> #include <...> @@ -133,6 +142,8 @@ For pacman: #include "anythingelse.h" ------------------------------------------- +Never directly include config.h. This will always be added via Makefiles. + GDB and Valgrind Usage ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/Makefile.am b/Makefile.am index 6b24a4aa..0010a3eb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,8 +1,10 @@ -SUBDIRS = lib/libalpm src/util src/pacman scripts etc test/pacman test/util contrib +SUBDIRS = lib/libalpm src/util src/pacman scripts etc test/pacman test/util test/scripts if WANT_DOC SUBDIRS += doc endif +DIST_SUBDIRS = $(SUBDIRS) contrib + ACLOCAL_AMFLAGS = -I m4 --install # Make sure we test and build manpages when doing distcheck @@ -21,15 +23,27 @@ dist_pkgdata_DATA = \ proto/ChangeLog.proto # run the pactest test suite and vercmp tests -check-local: test/pacman test/util src/pacman src/util +check-local: test-pacman test-pacsort test-vercmp test-parseopts + +test-pacman: test/pacman src/pacman LC_ALL=C $(PYTHON) $(top_srcdir)/test/pacman/pactest.py --debug=1 \ --test $(top_srcdir)/test/pacman/tests/*.py \ -p $(top_builddir)/src/pacman/pacman - $(SH) $(top_srcdir)/test/util/pacsorttest.sh \ + +test-pacsort: test/util src/util + $(BASH_SHELL) $(top_srcdir)/test/util/pacsorttest.sh \ $(top_builddir)/src/util/pacsort - $(SH) $(top_srcdir)/test/util/vercmptest.sh \ + +test-vercmp: test/util src/util + $(BASH_SHELL) $(top_srcdir)/test/util/vercmptest.sh \ $(top_builddir)/src/util/vercmp +test-parseopts: test/scripts scripts + $(BASH_SHELL) $(top_srcdir)/test/scripts/parseopts_test.sh \ + $(top_srcdir)/scripts/library/parseopts.sh + $(BASH_SHELL) $(top_srcdir)/test/scripts/human_to_size_test.sh \ + $(top_srcdir)/scripts/library/human_to_size.sh + # create the pacman DB and cache directories upon install install-data-local: for dir in "$(DESTDIR)$(localstatedir)/lib/pacman" "$(DESTDIR)$(localstatedir)/cache/pacman/pkg"; do \ @@ -41,4 +55,6 @@ update-po: $(MAKE) -C scripts/po update-po $(MAKE) -C src/pacman/po update-po +.PHONY: test-pacman test-pacsort test-vercmp test-parseopts update-po + # vim:set ts=2 sw=2 noet: @@ -389,7 +389,7 @@ API CHANGES BETWEEN 3.5 AND 4.0 - PM_ prefixes for enum values are now ALPM_ - pm prefixes for structs and enums are now alpm_ - alpm_initialize now has parameters: char *root, char *dbpath, - _alpm_errno_t *err and returns an alpm_handle_t struct. + alpm_errno_t *err and returns an alpm_handle_t struct. - alpm_release now takes an alpm_handle_t *. - alpm_db_register_sync() now requires a extra parameter of a alpm_siglevel_t. - alpm_pkg_load() now requires an extra parameter of an alpm_siglevel_t diff --git a/autoclean.sh b/autoclean.sh index 8f45d561..900f3536 100755 --- a/autoclean.sh +++ b/autoclean.sh @@ -1,9 +1,9 @@ #!/bin/sh -xu [ -f Makefile ] && make distclean + rm -rf autom4te.cache -rm -f {Makefile.in,Makefile} -rm -f {config.h.in,config.h} +rm -f config.h.in config.h rm -f config.status rm -f configure rm -f stamp* @@ -11,22 +11,12 @@ rm -f aclocal.m4 rm -f compile rm -f libtool -rm -f lib/libalpm/{Makefile.in,Makefile} -rm -f src/util/{Makefile.in,Makefile} -rm -f src/pacman/{Makefile.in,Makefile} -rm -f scripts/{Makefile.in,Makefile} -rm -f etc/{Makefile.in,Makefile} -rm -f etc/pacman.d/{Makefile.in,Makefile} -rm -f etc/abs/{Makefile.in,Makefile} -rm -f test/{pacman,util}{,/tests}/{Makefile.in,Makefile} -rm -f contrib/{Makefile.in,Makefile} -rm -f doc/{Makefile.in,Makefile} - rm -f test/pacman/*.pyc rm -f doc/html/*.html rm -f doc/man3/*.3 -rm -f {lib/libalpm,scripts,src/pacman}/po/{Makefile.in,Makefile} -rm -f {lib/libalpm,scripts,src/pacman}/po/POTFILES -rm -f {lib/libalpm,scripts,src/pacman}/po/stamp-po -rm -f {lib/libalpm,scripts,src/pacman}/po/*.gmo +find . \( -name 'Makefile' -o \ + -name 'Makefile.in' -o \ + -path '*/po/POTFILES' -o \ + -path '*/po/stamp-po' -o \ + -path '*/po/*.gmo' \) -exec rm -f {} + diff --git a/config.guess b/build-aux/config.guess index 28523784..28523784 100755 --- a/config.guess +++ b/build-aux/config.guess diff --git a/config.rpath b/build-aux/config.rpath index c492a93b..c492a93b 100755 --- a/config.rpath +++ b/build-aux/config.rpath diff --git a/config.sub b/build-aux/config.sub index 320e3038..320e3038 100755 --- a/config.sub +++ b/build-aux/config.sub diff --git a/depcomp b/build-aux/depcomp index df8eea7e..df8eea7e 100755 --- a/depcomp +++ b/build-aux/depcomp diff --git a/install-sh b/build-aux/install-sh index 3f83ce9b..3f83ce9b 100755 --- a/install-sh +++ b/build-aux/install-sh diff --git a/ltmain.sh b/build-aux/ltmain.sh index 5f505e27..5f505e27 100644 --- a/ltmain.sh +++ b/build-aux/ltmain.sh diff --git a/missing b/build-aux/missing index 28055d2a..28055d2a 100755 --- a/missing +++ b/build-aux/missing diff --git a/mkinstalldirs b/build-aux/mkinstalldirs index 4191a45d..4191a45d 100755 --- a/mkinstalldirs +++ b/build-aux/mkinstalldirs diff --git a/configure.ac b/configure.ac index 240d1c4c..7fe696a9 100644 --- a/configure.ac +++ b/configure.ac @@ -55,13 +55,22 @@ m4_define([pacman_version], AC_INIT([pacman], [pacman_version], [pacman-dev@archlinux.org]) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([build-aux]) AC_CANONICAL_HOST -AM_INIT_AUTOMAKE +AM_INIT_AUTOMAKE([1.11]) +AM_SILENT_RULES([yes]) +LT_INIT LIB_VERSION=`expr lib_current - lib_age`.lib_age.lib_revision LIB_VERSION_INFO="lib_current:lib_revision:lib_age" +# Respect empty CFLAGS during compiler tests +if test "x$CFLAGS" != "x"; then + CFLAGS="" +fi + # Set subsitution values for version stuff in Makefiles and anywhere else, # and put LIB_VERSION in config.h AC_SUBST(LIB_VERSION) @@ -88,6 +97,12 @@ AC_ARG_WITH(buildscript, AS_HELP_STRING([--with-buildscript=name], [set the build script name used by makepkg]), [BUILDSCRIPT=$withval], [BUILDSCRIPT=PKGBUILD]) +# Help line for changing shell used to run install scriptlets +AC_ARG_WITH(scriptlet-shell, + AS_HELP_STRING([--with-scriptlet-shell=shell], + [set the full path to the shell used to run install scriptlets]), + [SCRIPTLET_SHELL=$withval], [SCRIPTLET_SHELL=/bin/sh]) + # Help line for using OpenSSL AC_ARG_WITH(openssl, AS_HELP_STRING([--with-openssl], [use OpenSSL crypto implementations instead of internal routines]), @@ -98,8 +113,10 @@ AC_ARG_WITH(gpgme, AS_HELP_STRING([--with-gpgme], [use GPGME for PGP signature verification]), [], [with_gpgme=check]) -# Check for useable libcurl -LIBCURL_CHECK_CONFIG([yes], [7.19.4], [with_libcurl=yes], [with_libcurl=no]) +# Help line for using libcurl +AC_ARG_WITH(curl, + AS_HELP_STRING([--with-libcurl], [use libcurl for the internal downloader]), + [], [with_curl=check]) # Help line for documentation AC_ARG_ENABLE(doc, @@ -116,23 +133,43 @@ AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], [enable debugging support]), [debug=$enableval], [debug=no]) +# Help line for compiler warning flags +AC_ARG_ENABLE(warningflags, + AS_HELP_STRING([--enable-warningflags], [enable extra compiler warning flags]), + [warningflags=$enableval], [warningflags=no]) + # Help line for using git version in pacman version string AC_ARG_ENABLE(git-version, AS_HELP_STRING([--enable-git-version], [enable use of git version in version string if available]), [wantgitver=$enableval], [wantgitver=no]) +# Enable large file support if available (must be enabled before +# testing compilation against gpgme). +AC_SYS_LARGEFILE + # Checks for programs. AC_PROG_AWK AC_PROG_CC_C99 -AC_PROG_CXX AC_PROG_INSTALL -AC_PROG_LN_S -AC_PROG_MAKE_SET -AC_PROG_LIBTOOL -AC_PROG_RANLIB AC_CHECK_PROGS([PYTHON], [python2.7 python2.6 python2.5 python2 python], [false]) -AC_PATH_PROGS([BASH_SHELL], [bash bash4 bash3], [false]) +AC_PATH_PROGS([BASH_SHELL], [bash bash4], [false]) + +AS_IF([test "x$BASH_SHELL" = "xfalse"], + AC_MSG_WARN([*** bash >= 4.1.0 is required for pacman scripts]), + [bash_version_major=`$BASH_SHELL -c 'echo "${BASH_VERSINFO[[0]]}"'` + bash_version_minor=`$BASH_SHELL -c 'echo "${BASH_VERSINFO[[1]]}"'` + ok=yes + if test "$bash_version_major" -lt 4; then + ok=no + fi + if test "$bash_version_major" -eq 4 && test "$bash_version_minor" -lt 1; then + ok=no + fi + if test "$ok" = "no"; then + AC_MSG_ERROR([*** bash >= 4.1.0 is required for pacman scripts]) + fi + unset bash_version_major bash_version_minor ok]) # find installed gettext AM_GNU_GETTEXT([external], [need-ngettext]) @@ -142,34 +179,72 @@ AC_CHECK_LIB([m], [fabs], , AC_MSG_ERROR([libm is needed to compile pacman!])) # Check for libarchive -AC_CHECK_LIB([archive], [archive_read_data], , - AC_MSG_ERROR([libarchive is needed to compile pacman!])) +PKG_CHECK_MODULES(LIBARCHIVE, [libarchive >= 2.8.0], , + AC_MSG_ERROR([*** libarchive >= 2.8.0 is needed to compile pacman!])) # Check for OpenSSL -AC_MSG_CHECKING(whether to link with libssl) -AS_IF([test "x$with_openssl" != "xno"], - [AC_MSG_RESULT(yes) - AC_CHECK_LIB([ssl], [MD5_Final], , - [if test "x$with_openssl" != "xcheck"; then - AC_MSG_FAILURE([--with-openssl was given, but -lssl was not found]) - fi], - [-lcrypto]) - with_openssl=$ac_cv_lib_ssl_MD5_Final], - AC_MSG_RESULT(no)) -AM_CONDITIONAL([HAVE_LIBSSL], [test "x$with_openssl" = "xyes"]) +have_openssl=no +if test "x$with_openssl" != "xno"; then + PKG_CHECK_MODULES(LIBSSL, [libcrypto], + [AC_DEFINE(HAVE_LIBSSL, 1, [Define if libcrypto is available]) have_openssl=yes], have_openssl=no) + if test "x$have_openssl" = xno -a "x$with_openssl" = xyes; then + AC_MSG_ERROR([*** openssl support requested but libraries not found]) + fi +fi +AM_CONDITIONAL(HAVE_LIBSSL, [test "$have_openssl" = "yes"]) + +# Check for libcurl +have_libcurl=no +if test "x$with_libcurl" != "xno"; then + PKG_CHECK_MODULES(LIBCURL, [libcurl >= 7.19.4], + [AC_DEFINE(HAVE_LIBCURL, 1, [Define if libcurl is available]) have_libcurl=yes], have_libcurl=no) + if test "x$have_libcurl" = xno -a "x$with_libcurl" = xyes; then + AC_MSG_ERROR([*** libcurl >= 7.19.4 is required for internal downloader support]) + fi +fi +AM_CONDITIONAL(HAVE_LIBCURL, [test "$have_libcurl" = "yes"]) # Check for gpgme AC_MSG_CHECKING(whether to link with libgpgme) AS_IF([test "x$with_gpgme" != "xno"], - [AC_MSG_RESULT(yes) - AC_CHECK_LIB([gpgme], [gpgme_check_version], , - [if test "x$with_gpgme" != "xcheck"; then - AC_MSG_FAILURE([--with-ggpme was given, but -lgpgme was not found]) - fi], - [-lgpgme]) - with_gpgme=$ac_cv_lib_gpgme_gpgme_check_version], - AC_MSG_RESULT(no)) -AM_CONDITIONAL([HAVE_LIBGPGME], [test "x$with_gpgme" = "xyes"]) + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no])]) + +have_gpgme=no +AS_IF([test "x$with_gpgme" != "xno"], + [AM_PATH_GPGME([1.3.0], + [LIBS_save="$LIBS" + CPPFLAGS_save="$CPPFLAGS" + CFLAGS_save="$CFLAGS" + + LIBS="$LIBS $GPGME_LIBS" + CPPFLAGS="$CPPFLAGS $GPGME_CPPFLAGS" + CFLAGS="$CFLAGS $GPGME_CFLAGS" + + AC_MSG_CHECKING([for sane gpgme]) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[#include <gpgme.h>]], + [[return gpgme_check_version("1.3.0");]])], + [AC_MSG_RESULT([yes]) + have_gpgme=yes + AC_DEFINE([HAVE_LIBGPGME], [1], [Define if gpgme should be used to provide GPG signature support.])], + [AC_MSG_RESULT([no]) + have_gpgme=no + unset GPGME_LIBS + unset GPGME_CFLAGS] + AS_IF([test "x$with_gpgme" = "xyes"], + [AC_MSG_FAILURE([*** gpgme >= 1.3.0 is needed for GPG signature support])]) + )], + [with_gpgme=no])] + [LIBS="$LIBS_save" + CPPFLAGS="$CPPFLAGS_save" + CFLAGS="$CFLAGS_save" + unset CPPFLAGS_save + unset CFLAGS_save]) +AS_IF([test "x$have_gpgme" = xno -a "x$with_gpgme" = xyes], + [AC_MSG_FAILURE([--with-gpgme was given, but gpgme was not found])]) +AM_CONDITIONAL([HAVE_LIBGPGME], [test "x$have_gpgme" = "xyes"]) # Checks for header files. AC_CHECK_HEADERS([fcntl.h float.h glob.h libintl.h limits.h locale.h \ @@ -203,6 +278,7 @@ AC_CHECK_FUNCS([dup2 getcwd geteuid getmntinfo gettimeofday memmove memset \ mkdir realpath regcomp rmdir setenv setlocale strcasecmp \ strchr strcspn strdup strerror strndup strrchr strsep strstr \ strtol swprintf tcflush wcwidth uname]) +AC_CHECK_MEMBERS([struct stat.st_blksize],,,[[#include <sys/stat.h>]]) # For the diskspace code FS_STATS_TYPE @@ -210,15 +286,13 @@ AC_CHECK_MEMBERS([struct statvfs.f_flag],,,[[#include <sys/statvfs.h>]]) AC_CHECK_MEMBERS([struct statfs.f_flags],,,[[#include <sys/param.h> #include <sys/mount.h>]]) -# Enable large file support if available -AC_SYS_LARGEFILE - # Check if we can use symbol visibility support in GCC GCC_VISIBILITY_CC # Check if we have -fgnu89-inline flag GCC_GNU89_INLINE_CC # Host-dependant definitions +INODECMD="stat -c '%i %n'" SIZECMD="stat -c %s" SEDINPLACE="sed -i" STRIP_BINARIES="--strip-all" @@ -226,15 +300,17 @@ STRIP_SHARED="--strip-unneeded" STRIP_STATIC="--strip-debug" case "${host_os}" in *bsd*) + INODECMD="stat -f '%i %n'" SIZECMD="stat -f %z" SEDINPLACE="sed -i \"\"" ;; cygwin*) host_os_cygwin=yes - CFLAGS="$CFLAGS -DCYGWIN" + AC_DEFINE([CYGWIN], [1], [Define if host OS is cygwin]) ;; darwin*) host_os_darwin=yes + INODECMD="/usr/bin/stat -f '%i %n'" SIZECMD="/usr/bin/stat -f %z" SEDINPLACE="/usr/bin/sed -i ''" STRIP_BINARIES="" @@ -246,6 +322,7 @@ esac AM_CONDITIONAL([CYGWIN], test "x$host_os_cygwin" = "xyes") AM_CONDITIONAL([DARWIN], test "x$host_os_darwin" = "xyes") AC_PATH_PROGS([DUPATH], [du], [du], [/usr/bin$PATH_SEPARATOR/bin] ) +AC_SUBST(INODECMD) AC_SUBST(SIZECMD) AC_SUBST(SEDINPLACE) AC_SUBST(STRIP_BINARIES) @@ -297,16 +374,49 @@ AC_MSG_CHECKING(for debug mode request) if test "x$debug" = "xyes" ; then AC_MSG_RESULT(yes) AC_DEFINE([PACMAN_DEBUG], , [Enable debug code]) - # Check for mcheck - AC_CHECK_HEADERS([mcheck.h]) # Check for -fstack-protector availability GCC_STACK_PROTECT_LIB GCC_STACK_PROTECT_CC GCC_FORTIFY_SOURCE_CC - CFLAGS="$CFLAGS -g -Wall -Werror" + WARNING_CFLAGS="-g -Wall -Werror" +else + AC_MSG_RESULT(no) + WARNING_CFLAGS="-Wall" +fi + +# Enable or disable compiler warning flags +AC_MSG_CHECKING(for excessive compiler warning flags) +if test "x$warningflags" = "xyes" ; then + AC_MSG_RESULT(yes) + CFLAGS_ADD([-Wcast-align], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wclobbered], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wempty-body], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wfloat-equal], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wformat-nonliteral], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wformat-security], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wignored-qualifiers], [WARNING_CFLAGS]) + CFLAGS_ADD([-Winit-self], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wlogical-op], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wmissing-declarations], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wmissing-field-initializers], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wmissing-parameter-type], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wmissing-prototypes], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wold-style-declaration], [WARNING_CFLAGS]) + CFLAGS_ADD([-Woverride-init], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wpointer-arith], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wredundant-decls], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wshadow], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wsign-compare], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wstrict-aliasing], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wstrict-overflow=5], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wstrict-prototypes], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wtype-limits], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wuninitialized], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wunused-but-set-parameter], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wunused-parameter], [WARNING_CFLAGS]) + CFLAGS_ADD([-Wwrite-strings], [WARNING_CFLAGS]) else AC_MSG_RESULT(no) - CFLAGS="$CFLAGS -Wall" fi # Enable or disable use of git version in pacman version string @@ -330,6 +440,7 @@ AM_CONDITIONAL(USE_GIT_VERSION, test "x$usegitver" = "xyes") # Set root directory AC_SUBST(ROOTDIR) +AC_DEFINE_UNQUOTED([ROOTDIR], "$ROOTDIR", [The location of the root operating directory]) # Set package file extension AC_SUBST(PKGEXT) AC_DEFINE_UNQUOTED([PKGEXT], "$PKGEXT", [The file extension used by pacman packages]) @@ -339,11 +450,15 @@ AC_DEFINE_UNQUOTED([SRCEXT], "$SRCEXT", [The file extension used by pacman sourc # Set makepkg build script name AC_SUBST(BUILDSCRIPT) AC_DEFINE_UNQUOTED([BUILDSCRIPT], "$BUILDSCRIPT", [The build script name used by makepkg]) +# Set shell used by install scriptlets +AC_SUBST(SCRIPTLET_SHELL) +AC_DEFINE_UNQUOTED([SCRIPTLET_SHELL], "$SCRIPTLET_SHELL", [The full path of the shell used to run install scriptlets]) # Configuration files AC_CONFIG_FILES([ lib/libalpm/Makefile lib/libalpm/po/Makefile.in +lib/libalpm/libalpm.pc src/pacman/Makefile src/pacman/po/Makefile.in src/util/Makefile @@ -353,6 +468,7 @@ doc/Makefile etc/Makefile test/pacman/Makefile test/pacman/tests/Makefile +test/scripts/Makefile test/util/Makefile contrib/Makefile Makefile @@ -373,13 +489,14 @@ ${PACKAGE_NAME}: compiler : ${CC} preprocessor flags : ${CPPFLAGS} - compiler flags : ${CFLAGS} + compiler flags : ${WARNING_CFLAGS} ${CFLAGS} defines : ${DEFS} - library flags : ${LIBS} + library flags : ${LIBS} ${LIBSSL_LIBS} ${LIBARCHIVE_LIBS} ${LIBCURL_LIBS} ${GPGME_LIBS} linker flags : ${LDFLAGS} Architecture : ${CARCH} Host Type : ${CHOST} + File inode command : ${INODECMD} Filesize command : ${SIZECMD} In-place sed command : ${SEDINPLACE} @@ -395,12 +512,14 @@ ${PACKAGE_NAME}: build script name : ${BUILDSCRIPT} Compilation options: - Use libcurl : ${with_libcurl} - Use GPGME : ${with_gpgme} - Use OpenSSL : ${with_openssl} + Use libcurl : ${have_libcurl} + Use GPGME : ${have_gpgme} + Use OpenSSL : ${have_openssl} Run make in doc/ dir : ${wantdoc} ${asciidoc} Doxygen support : ${usedoxygen} debug support : ${debug} + extra warning flags : ${warningflags} + use git version : ${wantgitver} " # vim:set ts=2 sw=2 noet: diff --git a/contrib/.gitignore b/contrib/.gitignore index 70d19093..afbca0fb 100644 --- a/contrib/.gitignore +++ b/contrib/.gitignore @@ -7,4 +7,6 @@ paclog-pkglist pacscripts pacsearch pacsysclean +rankmirrors +updpkgsums zsh_completion diff --git a/contrib/Makefile.am b/contrib/Makefile.am index a7dee54f..3641a085 100644 --- a/contrib/Makefile.am +++ b/contrib/Makefile.am @@ -1,12 +1,26 @@ -OURSCRIPTS = \ +# enforce that all scripts have a --help and --version option +AUTOMAKE_OPTIONS = std-options + +bin_SCRIPTS = \ + $(OURSCRIPTS) + +BASHSCRIPTS = \ bacman \ paccache \ pacdiff \ paclist \ paclog-pkglist \ pacscripts \ - pacsearch \ - pacsysclean + pacsysclean \ + rankmirrors \ + updpkgsums + +OTHERSCRIPTS = \ + pacsearch + +OURSCRIPTS = \ + $(BASHSCRIPTS) \ + $(OTHERSCRIPTS) OURFILES = \ bash_completion \ @@ -14,15 +28,17 @@ OURFILES = \ EXTRA_DIST = \ PKGBUILD.vim \ - bacman.in \ + bacman.sh.in \ bash_completion.in \ - paccache.in \ - paclog-pkglist.in \ - pacdiff.in \ - paclist.in \ - pacscripts.in \ + paccache.sh.in \ + paclog-pkglist.sh.in \ + pacdiff.sh.in \ + paclist.sh.in \ + pacscripts.sh.in \ pacsearch.in \ - pacsysclean.in \ + pacsysclean.sh.in \ + rankmirrors.sh.in + updpkgsums.sh.in \ vimprojects \ zsh_completion.in \ README @@ -30,38 +46,62 @@ EXTRA_DIST = \ # Files that should be removed, but which Automake does not know. MOSTLYCLEANFILES = $(OURSCRIPTS) $(OURFILES) *.tmp +if USE_GIT_VERSION +GIT_VERSION := $(shell sh -c 'git describe --abbrev=4 --dirty | sed s/^v//') +REAL_PACKAGE_VERSION = $(GIT_VERSION) +else +REAL_PACKAGE_VERSION = $(PACKAGE_VERSION) +endif + edit = sed \ -e 's|@sysconfdir[@]|$(sysconfdir)|g' \ -e 's|@localstatedir[@]|$(localstatedir)|g' \ + -e 's|@PACKAGE_VERSION[@]|$(REAL_PACKAGE_VERSION)|g' \ -e 's|@SIZECMD[@]|$(SIZECMD)|g' \ + -e 's|@SCRIPTNAME[@]|$@|g' \ -e '1s|!/bin/bash|!$(BASH_SHELL)|g' -$(OURSCRIPTS): Makefile - @echo ' ' GEN $@; - @$(RM) $@ $@.tmp - @$(edit) $(srcdir)/$@.in >$@.tmp - @chmod +x $@.tmp - @chmod a-w $@.tmp - @mv $@.tmp $@ +$(OTHERSCRIPTS): Makefile + $(AM_V_at)$(RM) $@ $@.tmp + $(AM_V_GEN)$(edit) $(srcdir)/$@.in >$@.tmp + $(AM_V_at)chmod +x,a-w $@.tmp + $(AM_V_at)mv $@.tmp $@ + +$(BASHSCRIPTS): Makefile + $(AM_V_at)$(RM) $@ + $(AM_V_GEN)test -f $(srcdir)/$@.sh.in && m4 -P -I $(srcdir) $(srcdir)/$@.sh.in | $(edit) >$@ + $(AM_V_at)chmod +x,a-w $@ + @$(BASH_SHELL) -O extglob -n $@ $(OURFILES): Makefile - @echo ' ' GEN $@; - @$(RM) $@ $@.tmp - @$(edit) $(srcdir)/$@.in >$@.tmp - @chmod a-w $@.tmp - @mv $@.tmp $@ + $(AM_V_at)$(RM) $@ $@.tmp + $(AM_V_GEN)$(edit) $(srcdir)/$@.in >$@.tmp + $(AM_V_at)chmod a-w $@.tmp + $(AM_V_at)mv $@.tmp $@ all-am: $(OURSCRIPTS) $(OURFILES) -bacman: $(srcdir)/bacman.in +install-data-local: + $(MKDIR_P) $(DESTDIR)$(sysconfdir)/bash_completion.d/ + $(INSTALL_DATA) bash_completion $(DESTDIR)$(sysconfdir)/bash_completion.d/pacman + $(MKDIR_P) $(DESTDIR)$(datarootdir)/zsh/site-functions/ + $(INSTALL_DATA) zsh_completion $(DESTDIR)$(datarootdir)/zsh/site-functions/_pacman + +uninstall-local: + $(RM) $(DESTDIR)$(sysconfdir)/bash_completion.d/pacman + $(RM) $(DESTDIR)$(datarootdir)/zsh/site-functions/_pacman + +bacman: $(srcdir)/bacman.sh.in bash_completion: $(srcdir)/bash_completion.in -paccache: $(srcdir)/paccache.in -pacdiff: $(srcdir)/pacdiff.in -paclist: $(srcdir)/paclist.in -paclog-pkglist: $(srcdir)/paclog-pkglist.in -pacscripts: $(srcdir)/pacscripts.in +paccache: $(srcdir)/paccache.sh.in $(top_srcdir)/scripts/library/parseopts.sh $(top_srcdir)/scripts/library/size_to_human.sh +pacdiff: $(srcdir)/pacdiff.sh.in +paclist: $(srcdir)/paclist.sh.in +paclog-pkglist: $(srcdir)/paclog-pkglist.sh.in +pacscripts: $(srcdir)/pacscripts.sh.in pacsearch: $(srcdir)/pacsearch.in -pacsysclean: $(srcdir)/pacsysclean.in +pacsysclean: $(srcdir)/pacsysclean.sh.in +rankmirrors: $(srcdir)/rankmirrors.sh.in +updpkgsums: $(srcdir)/updpkgsums.sh.in zsh_completion: $(srcdir)/zsh_completion.in # vim:set ts=2 sw=2 noet: diff --git a/contrib/PKGBUILD.vim b/contrib/PKGBUILD.vim index 4d69e4d9..65fe4895 100644 --- a/contrib/PKGBUILD.vim +++ b/contrib/PKGBUILD.vim @@ -69,8 +69,8 @@ syn match pbUrlGroup /^url=.*/ contains=pbValidUrl,pb_k_url,pbIllegalUrl,shDoubl " license syn keyword pb_k_license license contained " echo $(pacman -Ql licenses | grep '/usr/share/licenses/common/' | cut -d'/' -f6 | sort -u) -syn keyword pbLicense APACHE CCPL CDDL CPL EPL FDL FDL1.2 FDL1.3 GPL GPL2 GPL3 LGPL LGPL2.1 LGPL3 LPPL MPL PerlArtistic PHP PSF RALINK RUBY ZPL contained -" special cases from http://wiki.archlinux.org/index.php/Arch_Packaging_Standards +syn keyword pbLicense AGPL AGPL3 Apache APACHE Artistic2.0 CCPL CDDL CPL EPL FDL FDL1.2 FDL1.3 GPL GPL2 GPL3 LGPL LGPL2.1 LGPL3 LPPL MPL PerlArtistic PHP PSF RUBY W3C ZPL contained +" special cases from https://wiki.archlinux.org/index.php/Arch_Packaging_Standards syn keyword pbLicenseSpecial BSD MIT ZLIB Python contained syn match pbLicenseCustom /custom\(:[[:alnum:]]*\)*/ contained syn match pbIllegalLicense /[^='"() ]/ contained contains=pbLicenseCustom,pbLicenseSpecial,pbLicense @@ -108,7 +108,7 @@ syn match pbValidOptdepends /\([[:alnum:]]\|+\|-\|_\)*/ contained syn region pbOptdependsGroup start=/^optdepends=(/ end=/)/ contains=pb_k_optdepends,pbValidOptdepends,shDoubleQuote,shSingleQuote " checkdepends -syn keyword pb_k_ckdepends ckdepends contained +syn keyword pb_k_ckdepends checkdepends contained syn match pbValidCkdepends /\([[:alnum:]]\|+\|-\|_\)*/ contained syn region pbCkdependsGroup start=/^checkdepends=(/ end=/)/ contains=pb_k_ckdepends,pbValidCkdepends,shDoubleQuote,shSingleQuote @@ -176,6 +176,39 @@ hi def link pbSha1Quotes Keyword hi def link pbSha1Hash Error hi def link pbValidSha1sums Number +" sha256sums +syn keyword pb_k_sha256sums sha256sums contained +syn match pbIllegalSha256sums /[^='"()\/ ]/ contained contains=pbValidSha256sums +syn match pbValidSha256sums /\x\{64\}/ contained +syn region pbSha256sumsGroup start=/^sha256sums/ end=/)/ contains=pb_k_sha256sums,pbSha256Quotes,pbSha256Hash,pbIllegalSha256sums keepend +syn match pbSha256Quotes /'.*'\|".*"/ contained contains=pbSha256Hash,pbIllegalSha256sums +syn match pbSha256Hash /\x\+/ contained contains=pbValidSha256sums +hi def link pbSha256Quotes Keyword +hi def link pbSha256Hash Error +hi def link pbValidSha256sums Number + +" sha384sums +syn keyword pb_k_sha384sums sha384sums contained +syn match pbIllegalSha384sums /[^='"()\/ ]/ contained contains=pbValidSha384sums +syn match pbValidSha384sums /\x\{96\}/ contained +syn region pbSha384sumsGroup start=/^sha384sums/ end=/)/ contains=pb_k_sha384sums,pbSha384Quotes,pbSha384Hash,pbIllegalSha384sums keepend +syn match pbSha384Quotes /'.*'\|".*"/ contained contains=pbSha384Hash,pbIllegalSha384sums +syn match pbSha384Hash /\x\+/ contained contains=pbValidSha384sums +hi def link pbSha384Quotes Keyword +hi def link pbSha384Hash Error +hi def link pbValidSha384sums Number + +" sha512sums +syn keyword pb_k_sha512sums sha512sums contained +syn match pbIllegalSha512sums /[^='"()\/ ]/ contained contains=pbValidSha512sums +syn match pbValidSha512sums /\x\{128\}/ contained +syn region pbSha512sumsGroup start=/^sha512sums/ end=/)/ contains=pb_k_sha512sums,pbSha512Quotes,pbSha512Hash,pbIllegalSha512sums keepend +syn match pbSha512Quotes /'.*'\|".*"/ contained contains=pbSha512Hash,pbIllegalSha512sums +syn match pbSha512Hash /\x\+/ contained contains=pbValidSha512sums +hi def link pbSha512Quotes Keyword +hi def link pbSha512Hash Error +hi def link pbValidSha512sums Number + " options syn keyword pb_k_options options contained syn match pbOptions /\(no\)\?\(strip\|docs\|libtool\|emptydirs\|zipman\|ccache\|distcc\|makeflags\|buildflags\)/ contained @@ -258,6 +291,15 @@ hi def link pbIllegalMd5sums Error hi def link pb_k_sha1sums pbKeywords hi def link pbIllegalSha1sums Error +hi def link pb_k_sha256sums pbKeywords +hi def link pbIllegalSha256sums Error + +hi def link pb_k_sha384sums pbKeywords +hi def link pbIllegalSha384sums Error + +hi def link pb_k_sha512sums pbKeywords +hi def link pbIllegalSha512sums Error + hi def link pb_k_options pbKeywords hi def link pbOptionsDeprec Todo hi def link pbIllegalOption Error diff --git a/contrib/bacman.in b/contrib/bacman.sh.in index f7e3202f..7895a40c 100755..100644 --- a/contrib/bacman.in +++ b/contrib/bacman.sh.in @@ -24,16 +24,21 @@ shopt -s extglob shopt -s nullglob -readonly progname="bacman" -readonly progver="0.2.1" +declare -r myname='bacman' +declare -r myver='@PACKAGE_VERSION@' # # User Friendliness # usage() { echo "This program recreates a package using pacman's db and system files" - echo "Usage: $progname <installed package name>" - echo "Example: $progname kernel26" + echo "Usage: $myname <installed package name>" + echo "Example: $myname kernel26" +} + +version() { + printf "%s %s\n" "$myname" "$myver" + echo 'Copyright (C) 2008 locci <carlocci_at_gmail_dot_com>' } if (( $# != 1 )); then @@ -41,14 +46,11 @@ if (( $# != 1 )); then exit 1 fi -if [[ $1 == "--help" || $1 == "-h" ]]; then +if [[ $1 = -@(h|-help) ]]; then usage exit 0 -fi - -if [[ $1 == "--version" || $1 == "-v" ]]; then - echo "$progname version $progver" - echo "Copyright (C) 2008 locci" +elif [[ $1 = -@(V|-version) ]]; then + version exit 0 fi @@ -62,7 +64,7 @@ if (( EUID )); then /usr/bin/fakeroot -u -- "$0" "$@" exit $? else - echo "WARNING: installing fakeroot or running ${progname} as root is required to" + echo "WARNING: installing fakeroot or running $myname as root is required to" echo " preserve the ownership permissions of files in some packages" echo "" fi @@ -151,7 +153,7 @@ while read i; do echo "" echo "ERROR: unable to add /$i to the package" echo " If your user does not have permssion to read this file then" - echo " you will need to run $progname as root" + echo " you will need to run $myname as root" rm -rf "$work_dir" exit 1 fi @@ -177,7 +179,7 @@ pkg_size=$(du -sk | awk '{print $1 * 1024}') # TODO adopt makepkg's write_pkginfo() into this or scripts/library # echo Generating .PKGINFO metadata... -echo "# Generated by $progname $progver" > .PKGINFO +echo "# Generated by $myname $myver" > .PKGINFO if [[ $INFAKEROOT == "1" ]]; then echo "# Using $(fakeroot -v)" >> .PKGINFO fi @@ -303,4 +305,3 @@ echo Done exit 0 # vim: set ts=2 sw=2 noet: - diff --git a/contrib/bash_completion.in b/contrib/bash_completion.in index 8983c92b..b0901af2 100644 --- a/contrib/bash_completion.in +++ b/contrib/bash_completion.in @@ -27,17 +27,44 @@ _arch_incomp() { local r="\s-(-${1#* }\s|\w*${1% *})"; [[ $COMP_LINE =~ $r ]] } +_pacman_keyids() { + \pacman-key --list-keys 2>/dev/null | awk ' + $1 == "pub" { + # key id + split($2, a, "/"); print a[2] + } + $1 == "uid" { + # email + if (match($NF, /<[^>]+>/)) + print substr($NF, RSTART + 1, RLENGTH - 2) + }' +} + _pacman_key() { - local cur opts prev + local o cur opts prev wantfiles COMPREPLY=() _get_comp_words_by_ref cur prev - if [[ $cur = -* && - $prev != -@(a|-add|c|-config|g|-gpgdir|h|-help|import?(-trustdb)) ]]; then - opts=('add delete export finger help list-keys recv-keys updatedb verify version - config edit-key gpgdir import import-trustdb init keyserver list-sigs - lsign-key populate refresh-keys' - 'a d e f h l r u v V') + opts=('add delete export finger help list-keys recv-keys updatedb verify + version config edit-key gpgdir import import-trustdb init keyserver + list-sigs lsign-key populate refresh-keys' + 'a d e f h l r u v V') + + # operations for which we want to complete keyids + for o in 'd delete' 'e export' 'f finger' 'l list-keys' 'r recv-keys' \ + 'edit-key' 'list-sigs' 'refresh-keys'; do + _arch_incomp "$o" && break + unset o + done + + # options for which we want file completion + wantfiles='-@(c|-config|g|-gpgdir)' + + if [[ $prev = 'pacman-key' || ( $cur = -* && $prev != $wantfiles ) ]]; then _arch_ptr2comp opts + elif [[ $prev = @(-k|--keyserver) ]]; then + return + elif [[ $prev != $wantfiles && $o ]]; then + COMPREPLY=($(compgen -W '$(_pacman_keyids)' -- "$cur")) fi true } @@ -47,9 +74,9 @@ _makepkg() { COMPREPLY=() _get_comp_words_by_ref cur prev if [[ $cur = -* && ! $prev =~ ^-(-(config|help)$|\w*[Chp]) ]]; then - opts=('allsource asroot check clean config force geninteg help holdver ignorearch - install log nobuild nocheck nocolor noconfirm nodeps noextract noprogressbar - nosign pkg repackage rmdeps sign skipinteg source syncdeps' + opts=('allsource asdeps asroot check clean config force geninteg help holdver ignorearch + install log nobuild nocheck nocolor noconfirm nodeps noextract + noprogressbar nosign pkg repackage rmdeps sign skipinteg source syncdeps' 'A L R S c d e f g h i m o p r s') _arch_ptr2comp opts fi @@ -76,8 +103,8 @@ _pacman() { remove=('cascade dbonly nodeps nosave print recursive unneeded' 'c n p s u') sync=('asdeps asexplicit clean dbonly downloadonly force groups ignore ignoregroup info list needed nodeps print refresh recursive search sysupgrade' - 'c f g i l p s u w y') - upgrade=('asdeps asexplicit force needed nodeps print recursive' 'f p') + 'c g i l p s u w y') + upgrade=('asdeps asexplicit force needed nodeps print recursive' 'p') common=('arch cachedir config dbpath debug help logfile noconfirm noprogressbar noscriptlet quiet root verbose' 'b d h q r v') core=('database help query remove sync upgrade version' 'D Q R S U V h') @@ -111,18 +138,11 @@ _pacman() { true } -if [[ $(type -t compopt) = "builtin" ]]; then - _pacman_file() { - compopt -o filenames; _filedir 'pkg.tar*' - } - complete -F _pacman -o default pacman -else - _pacman_file() { - _filedir 'pkg.tar*' - } - complete -F _pacman -o filenames -o default pacman -fi +_pacman_file() { + compopt -o filenames; _filedir 'pkg.tar*' +} +complete -F _pacman -o default pacman complete -F _makepkg -o default makepkg complete -F _pacman_key -o default pacman-key diff --git a/contrib/paccache.in b/contrib/paccache.sh.in index a9e5bfbc..e8136559 100755..100644 --- a/contrib/paccache.in +++ b/contrib/paccache.sh.in @@ -20,6 +20,9 @@ shopt -s extglob +declare -r myname='paccache' +declare -r myver='@PACKAGE_VERSION@' + declare -a candidates=() cmdopts=() whitelist=() blacklist=() declare -i delete=0 dryrun=0 filecount=0 move=0 needsroot=0 totalsaved=0 verbose=0 declare cachedir=@localstatedir@/cache/pacman/pkg delim=$'\n' keep=3 movedir= scanarch= @@ -39,6 +42,8 @@ die() { exit 1 } +m4_include(../scripts/library/parseopts.sh) + # reads a list of files on stdin and prints out deletion candidates pkgfilter() { # there's whitelist and blacklist parameters passed to this @@ -103,29 +108,10 @@ pkgfilter() { }' "${@:3}" } -size_to_human() { - awk -v size="$1" ' - BEGIN { - suffix[1] = "B" - suffix[2] = "KiB" - suffix[3] = "MiB" - suffix[4] = "GiB" - suffix[5] = "TiB" - count = 1 - - while (size > 1024) { - size /= 1024 - count++ - } - - sizestr = sprintf("%.2f", size) - sub(/\.?0+$/, "", sizestr) - printf("%s %s", sizestr, suffix[count]) - }' -} +m4_include(../scripts/library/size_to_human.sh) runcmd() { - if (( needsroot )); then + if (( needsroot && EUID != 0 )); then msg "Privilege escalation required" if sudo -v &>/dev/null && sudo -l &>/dev/null; then sudo "$@" @@ -174,70 +160,101 @@ summarize() { usage() { cat <<EOF -usage: ${0##*/} <operation> [options] [targets...] +usage: $myname <operation> [options] [targets...] -${0##*/} is a flexible pacman cache cleaning utility, which has numerous +$myname is a flexible pacman cache cleaning utility, which has numerous options to help control how much, and what, is deleted from any directory containing pacman package tarballs. Operations: - -d perform a dry run, only finding candidate packages. - -m <movedir> move candidate packages to 'movedir'. - -r remove candidate packages. + -d, --dryrun perform a dry run, only finding candidate packages. + -m, --move <dir> move candidate packages to 'movedir'. + -r, --remove remove candidate packages. Options: - -a <arch> scan for 'arch' (default: all architectures). - -c <cachedir> scan 'cachedir' for packages (default: @localstatedir@/cache/pacman/pkg). - -f apply force to mv(1) and rm(1) operations. - -h display this help message. - -i <pkgs> ignore 'pkgs', which is a comma separated. Alternatively, - specify '-' to read package names from stdin, newline delimited. - -k <num> keep 'num' of each package in 'cachedir' (default: 3). - -u target uninstalled packages. - -v increase verbosity. specify up to 3 times. - -z use null delimiters for candidate names (only with -v and -vv) + -a, --arch <arch> scan for 'arch' (default: all architectures). + -c, --cachedir <dir> scan 'cachedir' for packages (default: @localstatedir@/cache/pacman/pkg). + -f, --force apply force to mv(1) and rm(1) operations. + -h, --help display this help message and exit. + -i, --ignore <pkgs> ignore 'pkgs', comma separated. Alternatively, specify '-' to + read package names from stdin, newline delimited. + -k, --keep <num> keep 'num' of each package in 'cachedir' (default: 3). + -u, --uninstalled target uninstalled packages. + -v, --verbose increase verbosity. specify up to 3 times. + -z, --null use null delimiters for candidate names (only with -v and -vv) EOF } -if (( ! UID )); then - error "Do not run this script as root. You will be prompted for privilege escalation." - exit 42 -fi +version() { + printf "%s %s\n" "$myname" "$myver" + echo 'Copyright (C) 2011 Dave Reisner <dreisner@archlinux.org>' +} + +OPT_SHORT=':a:c:dfhi:k:m:rsuVvz' +OPT_LONG=('arch:' 'cachedir:' 'dryrun' 'force' 'help' 'ignore:' 'keep:' 'move' + 'remove' 'uninstalled' 'version' 'verbose' 'null') -while getopts ':a:c:dfhi:k:m:rsuvz' opt; do - case $opt in - a) scanarch=$OPTARG ;; - c) cachedir=$OPTARG ;; - d) dryrun=1 ;; - f) cmdopts=(-f) ;; - h) usage +if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then + exit 1 +fi +set -- "${OPTRET[@]}" +unset OPT_SHORT OPT_LONG OPTRET + +while :; do + case $1 in + -a|--arch) + scanarch=$2 + shift ;; + -c|--cachedir) + cachedir=$2 + shift ;; + -d|--dryrun) + dryrun=1 ;; + -f|--force) + cmdopts=(-f) ;; + -h|--help) + usage exit 0 ;; - i) if [[ $OPTARG = '-' ]]; then - [[ ! -t 0 ]] && IFS=$'\n' read -r -d '' -a ign - else - IFS=',' read -r -a ign <<< "$OPTARG" - fi - blacklist+=("${ign[@]}") - unset i ign ;; - k) keep=$OPTARG + -i|--ignore) + if [[ $2 = '-' ]]; then + [[ ! -t 0 ]] && IFS=$'\n' read -r -d '' -a ign + else + IFS=',' read -r -a ign <<< "$2" + fi + blacklist+=("${ign[@]}") + unset i ign + shift ;; + -k|--keep) + keep=$2 if [[ -z $keep || -n ${keep//[0-9]/} ]]; then die 'argument to option -k must be a non-negative integer' else keep=$(( 10#$keep )) - fi ;; - m) move=1 movedir=$OPTARG ;; - r) delete=1 ;; - u) IFS=$'\n' read -r -d '' -a ign < <(pacman -Qq) - blacklist+=("${ign[@]}") - unset ign ;; - v) (( ++verbose )) ;; - z) delim='\0' ;; - :) die "option '--%s' requires an argument" "$OPTARG" ;; - ?) die "invalid option -- '%s'" "$OPTARG" ;; + fi + shift ;; + -m|--move) + move=1 movedir=$2 + shift ;; + -r|--remove) + delete=1 ;; + -u|--uninstalled) + IFS=$'\n' read -r -d '' -a ign < <(pacman -Qq) + blacklist+=("${ign[@]}") + unset ign ;; + -V|--version) + version + exit 0 ;; + -v|--verbose) + (( ++verbose )) ;; + -z|--null) + delim='\0' ;; + --) + shift + break 2 ;; esac + shift done -shift $(( OPTIND - 1 )) # remaining args are a whitelist whitelist=("$@") diff --git a/contrib/pacdiff.in b/contrib/pacdiff.sh.in index 3f26f381..bfafda26 100755..100644 --- a/contrib/pacdiff.in +++ b/contrib/pacdiff.sh.in @@ -17,17 +17,25 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # +declare -r myname='pacdiff' +declare -r myver='@PACKAGE_VERSION@' + diffprog=${DIFFPROG:-vimdiff} diffsearchpath=${DIFFSEARCHPATH:-/etc} locate=0 usage() { - echo "pacdiff : a simple pacnew/pacorig/pacsave updater" - echo "Usage : pacdiff [-l]" - echo " -l/--locate makes pacdiff use locate rather than find" + echo "$myname : a simple pacnew/pacorig/pacsave updater" + echo "Usage : $myname [-l]" + echo " -l/--locate makes $myname use locate rather than find" echo " DIFFPROG variable allows to override the default vimdiff" echo " DIFFSEARCHPATH allows to override the default /etc path" - echo "Example : DIFFPROG=meld DIFFSEARCHPATH=\"/boot /etc /usr\" pacdiff" + echo "Example : DIFFPROG=meld DIFFSEARCHPATH=\"/boot /etc /usr\" $myname" +} + +version() { + printf "%s %s\n" "$myname" "$myver" + echo 'Copyright (C) 2007 Aaron Griffin <aaronmgriffin@gmail.com>' } cmd() { @@ -42,8 +50,12 @@ if [ $# -gt 0 ]; then case $1 in -l|--locate) locate=1;; - *) + -V|--version) + version; exit 0;; + -h|--help) usage; exit 0;; + *) + usage; exit 1;; esac fi diff --git a/contrib/paclist.in b/contrib/paclist.sh.in index 06b06f2c..7883e21b 100755..100644 --- a/contrib/paclist.in +++ b/contrib/paclist.sh.in @@ -17,6 +17,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +declare -r myname='paclist' +declare -r myver='@PACKAGE_VERSION@' + export TEXTDOMAIN='pacman' export TEXTDOMAINDIR='/usr/share/locale' @@ -27,13 +30,31 @@ if ! type gettext &>/dev/null; then } fi -if [[ -z $1 || $1 = -@(h|-help) ]]; then - printf '%s - List all packages installed from a given repo\n' "${0##*/}" - printf 'Usage: %s <repo>\n' "${0##*/}" - printf 'Example: %s testing\n' "${0##*/}" +usage() { + printf '%s - List all packages installed from a given repo\n' "$myname" + printf 'Usage: %s <repo>\n' "$myname" + printf 'Example: %s testing\n' "$myname" +} + +version() { + printf "%s %s\n" "$myname" "$myver" + echo 'Copyright (C) 2008 Dan McGee <dpmcgee@gmail.com>' + echo 'Copyright (C) 2011 Dave Reisner <dreisner@archlinux.org>' +} + +if [[ -z $1 ]]; then + usage exit 1 fi +if [[ $1 = -@(h|-help) ]]; then + usage + exit 0 +elif [[ $1 = -@(V|-version) ]]; then + version + exit 0 +fi + printf -v installed '[%s]' "$(gettext installed)" pacman -Sl $1 | awk -v i="$installed" '$NF == i { print $2,$3 }' diff --git a/contrib/paclog-pkglist.in b/contrib/paclog-pkglist.sh.in index 27dfd302..222bbc4c 100755..100644 --- a/contrib/paclog-pkglist.in +++ b/contrib/paclog-pkglist.sh.in @@ -17,15 +17,30 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +declare -r myname='paclog-pkglist' +declare -r myver='@PACKAGE_VERSION@' + export TEXTDOMAIN='pacman' export TEXTDOMAINDIR='/usr/share/locale' declare logfile=${1:-@localstatedir@/log/pacman.log} +usage() { + printf 'usage: %s [pacman log]\n' "$myname" + printf 'example: %s @localstatedir@/log/pacman.log\n' "$myname" + printf '\ndefaults to: @localstatedir@/log/pacman.log\n' +} + +version() { + printf "%s %s\n" "$myname" "$myver" + echo 'Copyright (C) 2011 Dave Reisner <dave@archlinux.org>' +} + if [[ $1 ]]; then if [[ $1 = -@(h|-help) ]]; then - printf 'usage: %s [pacman log]\n' "${0##*/}" - printf 'example: %s @localstatedir@/log/pacman.log\n' "${0##*/}" - printf '\ndefaults to: @localstatedir@/log/pacman.log\n' + usage + exit 0 + elif [[ $1 = -@(V|-version) ]]; then + version exit 0 elif [[ ! -e $logfile ]]; then printf $"target not found: %s\n" "$1" diff --git a/contrib/pacscripts.in b/contrib/pacscripts.sh.in index 37d3feae..84687145 100755..100644 --- a/contrib/pacscripts.in +++ b/contrib/pacscripts.sh.in @@ -24,8 +24,8 @@ set -o nounset set -o errexit -progname=$(basename $0) -progver="0.4" +declare -r myname='pacscripts' +declare -r myver='@PACKAGE_VERSION@' conf="@sysconfdir@/pacman.conf" @@ -47,14 +47,20 @@ error() { usage() { echo "This program prints out the {pre,post}_{install,remove,upgrade} scripts" echo "of a given package." - echo "Usage: $progname pkgname|pkgfile" + echo "Usage: $myname pkgname|pkgfile" echo echo " OPTIONS:" echo " -h, --help Print this help message" echo " -v, --version Print program name and version" echo - echo "Example: $progname gconf-editor" - echo "Example: $progname gconf-editor-2.24.1-1-x86_64.pkg.tar.gz" + echo "Example: $myname gconf-editor" + echo "Example: $myname gconf-editor-2.24.1-1-x86_64.pkg.tar.gz" +} + +version() { + printf "%s %s\n" "$myname" "$myver" + echo 'Copyright (c) 2009 Giulio "giulivo" Fidente <giulivo.navigante@gmail.com>' + echo 'Copyright (c) 2009 Xavier Chantry <shiningxc@gmail.com>' } spacman() { @@ -127,6 +133,6 @@ fi case "$1" in --help|-h) usage; exit 0 ;; - --version|-v) echo "$progname version $progver"; exit 0 ;; + --version|-V) version; exit 0 ;; *) print_scriptlet $1 ;; esac diff --git a/contrib/pacsearch.in b/contrib/pacsearch.in index db9d6ad1..b1db8abe 100755..100644 --- a/contrib/pacsearch.in +++ b/contrib/pacsearch.in @@ -24,22 +24,32 @@ use strict; use warnings; -my $progname = "pacsearch"; -my $version = "2.0"; +my $myname = 'pacsearch'; +my $myver = '@PACKAGE_VERSION@'; + +sub usage { + print "$myname - Add color and install information to a pacman -Ss search\n"; + print "Usage: $myname <pattern>\n"; + print "Example: $myname ^gnome\n"; +} + +sub version { + printf "%s %s\n", $myname, $myver; + print "Copyright (C) 2008-2011 Dan McGee <dan\@archlinux.org>\n\n"; + print "Based off original shell script version:\n"; + print "Copyright (C) 2006-2007 Dan McGee <dan\@archlinux.org>\n"; +} 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"; + usage; if ($#ARGV lt 0) { exit 1; } exit 0; } -if ($ARGV[0] eq "--version" || $ARGV[0] eq "-v") { - print "$progname version $version\n"; - print "Copyright (C) 2006-2011 Dan McGee\n"; +if ($ARGV[0] eq "--version" || $ARGV[0] eq "-V") { + version; exit 0; } diff --git a/contrib/pacsysclean.in b/contrib/pacsysclean.in deleted file mode 100755 index 9e25d39e..00000000 --- a/contrib/pacsysclean.in +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash - -# pacsysclean - Sort installed packages by increasing installed size. Useful for system clean-up. - -PACMAN_OPTS= - -usage() { - echo "pacsysclean - Sort installed packages by increasing installed size." - echo - echo "Usage: pacsysclean [options]" - echo - echo "Options:" - echo " -o <options> Specify custom pacman query options (e.g., dt)" - echo " -h, --help Show this help message and exit" -} - - -if [ -n "$1" ]; then - case "$1" in - -o) PACMAN_OPTS="${2}" ;; - -h|--help) usage; exit 0 ;; - *) usage; exit 1 ;; - esac -fi - -IFS=$'\n' -name="^Name.*: (.*)$" -size="^Installed Size.*: (.*) KiB$" - -[[ $PACMAN_OPTS && $PACMAN_OPTS != -* ]] && PACMAN_OPTS="-$PACMAN_OPTS" - -for line in $(LANG=C pacman -Qi $PACMAN_OPTS); do - if [[ $line =~ $name ]]; then - printf "%s\t" ${BASH_REMATCH[1]} - elif [[ $line =~ $size ]]; then - printf "%s\n" ${BASH_REMATCH[1]} - fi -done | sort -g -k2 | awk ' -BEGIN { - split("KiB MiB GiB TiB PiB EiB ZiB YiB", suffix) -} -function format_size(size) { - count = 1 - while (size + 0 > 1024) { - size /= 1024 - count++ - } - sizestr = sprintf("%.2f %s", size, suffix[count]) - return sizestr -} -{ - printf("%s\t%s\n", format_size($2), $1); -}' diff --git a/contrib/pacsysclean.sh.in b/contrib/pacsysclean.sh.in new file mode 100644 index 00000000..37219ab5 --- /dev/null +++ b/contrib/pacsysclean.sh.in @@ -0,0 +1,64 @@ +#!/bin/bash + +# pacsysclean - Sort installed packages by increasing installed size. Useful for system clean-up. + +declare -r myname='pacsysclean' +declare -r myver='@PACKAGE_VERSION@' + +PACMAN_OPTS= + +usage() { + echo "$myname - Sort installed packages by increasing installed size." + echo + echo "Usage: $myname [options]" + echo + echo "Options:" + echo " -o <options> Specify custom pacman query options (e.g., dt)" + echo " -h, --help Show this help message and exit" +} + +version() { + printf "%s %s\n" "$myname" "$myver" + echo 'Copyright (C) 2011 Eric Bélanger <snowmaniscool@gmail.com>' +} + + +if [ -n "$1" ]; then + case "$1" in + -o) PACMAN_OPTS="${2}" ;; + -h|--help) usage; exit 0 ;; + -V|--version) version; exit 0 ;; + *) usage; exit 1 ;; + esac +fi + +IFS=$'\n' +name="^Name.*: (.*)$" +size="^Installed Size.*: (.*) KiB$" + +[[ $PACMAN_OPTS && $PACMAN_OPTS != -* ]] && PACMAN_OPTS="-$PACMAN_OPTS" + +for line in $(LANG=C pacman -Qi $PACMAN_OPTS); do + if [[ $line =~ $name ]]; then + printf "%s\t" ${BASH_REMATCH[1]} + elif [[ $line =~ $size ]]; then + printf "%s\n" ${BASH_REMATCH[1]} + fi +done | sort -g -k2 | awk ' +BEGIN { + split("KiB MiB GiB TiB PiB EiB ZiB YiB", suffix) +} +function format_size(size) { + count = 1 + while (size + 0 > 1024) { + size /= 1024 + count++ + } + sizestr = sprintf("%.2f %s", size, suffix[count]) + return sizestr +} +{ + printf("%s\t%s\n", format_size($2), $1); +}' + +# vim: set ts=2 sw=2 noet: diff --git a/scripts/rankmirrors.sh.in b/contrib/rankmirrors.sh.in index 875a1439..875a1439 100644 --- a/scripts/rankmirrors.sh.in +++ b/contrib/rankmirrors.sh.in diff --git a/contrib/updpkgsums.sh.in b/contrib/updpkgsums.sh.in new file mode 100755 index 00000000..33e04d9c --- /dev/null +++ b/contrib/updpkgsums.sh.in @@ -0,0 +1,93 @@ +#!/bin/bash +# +# updpkgsums - update source checksums in-place in PKGBUILDs +# +# Copyright (C) 2012 Dave Reisner <dreisner@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 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/>. + +shopt -s extglob + +declare -r myname='updpkgsums' +declare -r myver='@PACKAGE_VERSION@' + +usage() { + printf 'usage: %s [buildfile]\n\n' "$myname" + printf ' -h, --help display this help message and exit\n' + printf ' -V, --version display version information and exit\n\n' + printf '%s will perform an in place update the checksums in the\n' "$myname" + printf 'path specified by [buildfile], defaulting to PKGBUILD in the current\n' + printf 'working directory.\n' +} + +version() { + printf "%s %s\n" "$myname" "$myver" + echo 'Copyright (C) 2012 Dave Reisner <dreisner@archlinux.org>' +} + +case $1 in + -h|--help) usage; exit ;; + -V|--version) version; exit ;; +esac + +buildfile=${1:-PKGBUILD} +if [[ ! -f $buildfile ]]; then + printf '==> ERROR: %s not found or is not a file\n' "$buildfile" + exit 1 +fi + +# Resolve any symlinks to avoid replacing the symlink with a file. But, we +# have to do this portably -- readlink's flags are inconsistent across OSes. +while [[ -L $buildfile ]]; do + buildfile=$(readlink "$buildfile") + if [[ $buildfile = */* ]]; then + cd "${buildfile%/*}" + buildfile=${buildfile##*/} + fi +done + +# cd into the directory with the build file. This avoids creating random src/ +# directories scattered about the filesystem, and avoids cases where we might +# not be able to write in the $PWD. +if [[ $buildfile = */* ]]; then + cd "${buildfile%/*}" + buildfile=${buildfile##*/} +fi + +# Check $PWD/ for permission to unlink the $buildfile and write a new one +if [[ ! -w . ]]; then + printf $'==> ERROR: No write permission in `%s\'\n' "$PWD" + exit 1 +fi + +{ + # Generate the new sums and try to unlink the file before writing stdin back + # into it. This final precaution shouldn't fail based on the previous checks, + # but it's better to be extra careful before unlinking files. + newsums=$(makepkg -g -p "$buildfile") && rm -f "$buildfile" && + exec awk -v newsums="$newsums" ' + /^[[:blank:]]*(md|sha)[[:digit:]]+sums=/,/\)[[:blank:]]*(#.*)?$/ { + if (!w) { + print newsums + w++ + } + next + } + + 1 + END { if (!w) print newsums } + ' > "$buildfile" +} < "$buildfile" + +# vim: set ts=2 sw=2 noet: diff --git a/contrib/zsh_completion.in b/contrib/zsh_completion.in index 2cfc946c..84ee93ca 100644 --- a/contrib/zsh_completion.in +++ b/contrib/zsh_completion.in @@ -1,4 +1,4 @@ -#compdef pacman pacman.static=pacman +#compdef pacman pacman.static=pacman pacman-key makepkg # copy this file to /usr/share/zsh/site-functions/_pacman @@ -32,8 +32,8 @@ _pacman_opts_common=( # options for passing to _arguments: options for --upgrade commands _pacman_opts_pkgfile=( '-d[Skip dependency checks]' - '-f[Overwrite conflicting files]' '--dbonly[Only remove database entry, do not remove files]' + '--force[Overwrite conflicting files]' '--needed[Do not reinstall up to date packages]' '--recursive[Reinstall all dependencies of target packages]' '*:package file:_files -g "*.pkg.tar*(.)"' @@ -85,7 +85,6 @@ _pacman_opts_sync_actions=( # options for passing to _arguments: options for --sync command _pacman_opts_sync_modifiers=( '-d[Skip dependency checks]' - '-f[Overwrite conflicting files]' '-i[View package information]' '-l[List all packages in a repository]' '-p[Print download URIs for each package to be installed]' @@ -98,6 +97,7 @@ _pacman_opts_sync_modifiers=( _pacman_completions_all_groups' '--asdeps[Install packages as non-explicitly installed]' '--asexplicit[Install packages as explicitly installed]' + '--force[Overwrite conflicting files]' ) # handles --help subcommand @@ -286,7 +286,7 @@ _pacman_get_command() { } # main dispatcher -_pacman() { +_pacman_zsh_comp() { case $words[2] in -Q*g*) # ipkg groups _arguments -s : \ @@ -332,5 +332,204 @@ _pacman() { esac } -# run the main dispatcher -_pacman "$@" +_key_shortopts=( + '-h[show help]' \ + '-a[Add the specified keys (empty for stdin)]: :_files' + '-d[Remove the Specified keyids]:*: :_keys' + '-e[Export the specified or all keyids]:*: :_keys' + '-f[List fingreprint for specidied or all keyids]:*: :_keys' + '-l[List the specified or all keys]:*: :_keys' + '-r[Fetch the specified keyids]:*: :_keys' + '-u[Update the trustdb of pacman]' + '-v[Verify the file specified by the signature]: :_files -g "*.sig"' + '-V[Show program version]' + ) + +_key_longopts=( + '--help[show help]' + '--add[Add the specified keys (empty for stdin)]: :_files' + '--delete[Remove the Specified keyids]:*: :_keys' + '--export[Export the specified or all keyids]:*: :_keys' + '--finger[List fingreprint for specidied or all keyids]:*: :_keys' + '--list-keys[List the specified or all keys]:*: :_keys' + '--recv-keys[Fetch the specified keyids]:*: :_keys' + '--updatedb[Update the trustdb of pacman]' + '--verify[Verify the file specified by the signature]: :_files -g "*.sig"' + '--version[Show program version]' + '--edit-key[Present a menu for key management task on keyids]:*: :_keys' + '--import[Imports pubring.gpg from dir(s)]: :_files -g "*.gpg"' + '--import-tb[Imports ownertrust values from trustdb.gpg in dir(s)]: :_files -g "*.gpg"' + '--init[Ensure the keyring is properly initialized]' + '--list-sigs[List keys and their signatures]:*: :_keys' + '--lsign-key[Locally sign the specified keyid]:*: :_keys' + '--populate[Reload the default keys from the (given) keyrings in '/usr/share/pacman/keyrings']: :_path_files -W /usr/share/pacman/keyrings' + '--refresh-keys[Update specified or all keys from a keyserver]:*: :_keys' + ) + +_pacman_key_options=( + '--config[Use an alternate config file (instead of /etc/pacman.con)]: :_files' + '--gpgdir[Set an alternate directory for GnuPG (instead of /etc/pacman.d/gnupg)]: :_files -/' + '--keyserver[Specify a keyserver to use if necessary]' + ) + +_pacman_key() { + case $words[CURRENT] in + --*) + _arguments -s : \ + "$_pacman_key_options[@]" \ + "$_key_longopts[@]" + ;; + -*) + _arguments -s : \ + "$_pacman_key_options[@]" \ + "$_key_shortopts[@]" \ + "$_key_longopts[@]" + ;; + *) + i=$#; + while [[ $words[$i] != -* ]] && [[ $words[$i] != "pacman-key" ]];do + i=$(($i-1)) + done + case $i in + --*) + _arguments -s : \ + "$_pacman_key_options[@]" \ + "$_key_longopts[@]" + ;; + -*) + _arguments -s : \ + "$_pacman_key_options[@]" \ + "$_key_shortopts[@]" \ + "$_key_longopts[@]" + ;; + *) return 1;; + esac + ;; + esac +} + +_keys() { + local keylist keys + keylist=$(pacman-key --list-keys 2>/dev/null | awk ' + $1 == "pub" { + # key id + split($2, a, "/"); print a[2] + } + $1 == "uid" { + # email + if (match($NF, /<[^>]+>/)) + print substr($NF, RSTART + 1, RLENGTH - 2) + #this adds support for names as well if that is ever added + } + $1 == "uid" { + for (i=2;i<NF;i++) {printf "%s%s",sep, $i;sep=" "}; printf "\n" + }' |sed -e 's/(.*)//g' -e 's/^\ //g' -e 's/\ *$//g' |uniq + ) + keys=(${(s:/:)${keylist//$'\n'/\/}}) + _describe -t modules 'keys in keyring' keys && return 0 +} + +_makepkg_shortopts=( + '*-s[Install missing dependencies with pacman]' + '*-i[Install package after successful build]' + '*-A[Ignore incomplete arch field in PKGBUILD]' + '*-c[Clean up work files after build]' + '*-d[Skip all dependency checks]' + '*-e[Do not extract source files (use existing src/ dir)]' + '*-f[Overwrite existing package]' + '*-g[Generate integrity checks for source files]' + '*-h[Show help message and exit]' + '*-L[Log package build process]' + '*-m[Disable colorized output messages]' + '*-o[Download and extract files only]' + '-p[Use an alternate build script (instead of 'PKGBUILD')]: :_files' + '*-r[Remove installed dependencies after a successful build]' + '*-R[Repackage contents of the package without rebuilding]' + '*-S[Generate a source-only tarball without downloading sources]' + ) + +_makepkg_action_none(){ + _arguments \ + "$_makepkg_shortopts[@]"\ + "$_makepkg_longopts[@]" +} +_makepkg_longopts=( + '--ignorearch[Ignore incomplete arch field in PKGBUILD]' + '--clean[Clean up work files after build]' + '--nodeps[Skip all dependency checks]' + '--noextract[Do not extract source files (use existing src/ dir)]' + '--force[Overwrite existing package]' + '--geninteg[Generate integrity checks for source files]' + '--help[Show help message and exit]' + '--install[Install package after successful build]' + '--log[Log package build process]' + '--nocolor[Disable colorized output messages]' + '--nobuild[Download and extract files only]' + '--rmdeps[Remove installed dependencies after a successful build]' + '--repackage[Repackage contents of the package without rebuilding]' + '--syncdeps[Install missing dependencies with pacman]' + '--source[Generate a source-only tarball without downloading sources]' + '--allsource[Generate a source-only tarball including downloaded source]' + '--asroot[Allow makepkg to run as root user]' + '--check[Run check() function in the PKGBUILD]' + '--config[Use an alternate config file instead of '/etc/makepkg.conf']: :_files' + '--holdver[Prevent automatic version bumping for development PKGBUILDs]' + '--key[Specify key to use for gpg signing instead of the default]: :_keys' + '--nocheck[Do not run the check() function in the PKGBUILD]' + '--nosign[Do not create a signature for the package]' + '--pkg[Only build listed packages from a split package]' + '--sign[Sign the resulting package with gpg]' + '--skipchecksums[Do not verify checksums of the source files]' + '--skipinteg[do not perform any verification checks on source files]' + '--skippgpcheck[Do not verify source files with PGP signatures]' + '--noconfirm[do not ask for confirmation when resolving dependencies]' + '--asdeps[Install packages as non-explicitly installed]' + '--noprogressbar[Do not show a progress bar when downloading files]' + ) +_makepkg(){ + case $words[CURRENT] in + -*) + _arguments -s -w : \ + "$_makepkg_shortopts[@]" \ + "$_makepkg_longopts[@]" + ;; + --* ) + _arguments -s \ + "$_makepkg_longopts[@]" + ;; + - )_makepkg_action_none ;; + * ) + i=$# + while [[ $words[i] != -* ]] && [[ $words[$i] != "makepkg" ]];do + i=$((i-1)); + done + case $words[$i] in + -*) + _arguments -s -w : \ + "$_makepkg_shortopts[@]" \ + "$_makepkg_longopts[@]" + ;; + --* ) + _arguments -s \ + "$_makepkg_longopts[@]" + ;; + - )_makepkg_action_none ;; + * ) return 1 ;; + esac + ;; + esac +} +_pacman_comp() { + case "$service" in + makepkg) + _makepkg "$@";; + pacman-key) + _pacman_key "$@";; + pacman) + _pacman_zsh_comp "$@";; + *) + _message "Error";; + esac +} + +_pacman_comp "$@" diff --git a/doc/Makefile.am b/doc/Makefile.am index dd37124f..bcb05b74 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -93,8 +93,12 @@ endif html: $(HTML_DOCS) -website: html - bsdtar czf website.tar.gz $(HTML_DOCS) \ +website: website.tar.gz + +.PHONY: html website + +website.tar.gz: html + $(AM_V_GEN)bsdtar czf $@ $(HTML_DOCS) \ asciidoc-override.css \ -C /etc/asciidoc/stylesheets/ \ asciidoc.css \ @@ -122,15 +126,15 @@ A2X_OPTS = \ # These rules are due to the includes and files of the asciidoc text $(ASCIIDOC_MANS): asciidoc.conf footer.txt Makefile.am - a2x $(A2X_OPTS) --asciidoc-opts="$(ASCIIDOC_OPTS) --out-file=./$@.xml" $(srcdir)/$@.txt + $(AM_V_GEN)a2x $(A2X_OPTS) --asciidoc-opts="$(ASCIIDOC_OPTS) --out-file=./$@.xml" $(srcdir)/$@.txt %.html: %.txt - asciidoc $(ASCIIDOC_OPTS) $*.txt - dos2unix $@ + $(AM_V_GEN)asciidoc $(ASCIIDOC_OPTS) -o - $*.txt | \ + sed -e 's/\r$$//' > $@ HACKING.html: ../HACKING - asciidoc $(ASCIIDOC_OPTS) -o $@ ../HACKING - dos2unix $@ + $(AM_V_GEN)asciidoc $(ASCIIDOC_OPTS) -o - ../HACKING | \ + sed -e 's/\r$$//' > $@ # Customizations for certain HTML docs $(HTML_MANPAGES): asciidoc.conf footer.txt Makefile.am diff --git a/doc/PKGBUILD.5.txt b/doc/PKGBUILD.5.txt index ffbb69bd..062b1ab6 100644 --- a/doc/PKGBUILD.5.txt +++ b/doc/PKGBUILD.5.txt @@ -121,9 +121,10 @@ of the corresponding source file. *md5sums (array)*:: This array contains an MD5 hash for every source file specified in the source array (in the same order). makepkg will use this to verify source - file integrity during subsequent builds. To easily generate md5sums, run - `makepkg -g >> PKGBUILD`. If desired, move the md5sums line to an - appropriate location. + file integrity during subsequent builds. If 'SKIP' is put in the array + in place of a normal hash, the integrity check for that source file will + be skipped. To easily generate md5sums, run ``makepkg -g >> PKGBUILD''. + If desired, move the md5sums line to an appropriate location. *sha1sums, sha256sums, sha384sums, sha512sums (arrays)*:: Alternative integrity checks that makepkg supports; these all behave @@ -253,10 +254,10 @@ A normal sync or upgrade will not use its value. with distcc. *buildflags*;; - Allow the use of user-specific buildflags (CFLAGS, CXXFLAGS, LDFLAGS) - during build as specified in linkman:makepkg.conf[5]. More useful in - its negative form `!buildflags` with select packages that have problems - building with custom buildflags. + Allow the use of user-specific buildflags (CPPFLAGS, CFLAGS, CXXFLAGS, + LDFLAGS) during build as specified in linkman:makepkg.conf[5]. More + useful in its negative form `!buildflags` with select packages that + have problems building with custom buildflags. *makeflags*;; Allow the use of user-specific makeflags during build as specified @@ -295,6 +296,15 @@ If you create any variables of your own in the build function, it is recommended to use the bash `local` keyword to scope the variable to inside the build function. +prepare() Function +------------------ +An optional prepare() function can be specified in which operations that are +to be run in order to prepare the sources for building (such as patching) are +performed. This function is run after the source extraction and before the +build() function and is skipped when source extraction is skipped. The +function is run in `bash -e` mode, meaning any command that exits with a +non-zero status will cause the function to exit. + check() Function ---------------- An optional check() function can be specified in which a packages test-suite @@ -323,9 +333,9 @@ Each split package uses a corresponding packaging function with name All options and directives for the split packages default to the global values given in the PKGBUILD. Nevertheless, the following ones can be overridden within each split package's packaging function: -`pkgver`, `pkgrel`, `epoch`, `pkgdesc`, `arch`, `license`, `groups`, `depends`, -`optdepends`, `provides`, `conflicts`, `replaces`, `backup`, `options`, -`install` and `changelog`. +`pkgver`, `pkgrel`, `epoch`, `pkgdesc`, `arch`, `url`, `license`, `groups`, +`depends`, `optdepends`, `provides`, `conflicts`, `replaces`, `backup`, +`options`, `install` and `changelog`. An optional global directive is available when building a split package: diff --git a/doc/makepkg.8.txt b/doc/makepkg.8.txt index f693a5a8..c24e89e3 100644 --- a/doc/makepkg.8.txt +++ b/doc/makepkg.8.txt @@ -59,11 +59,11 @@ Options installed. *-e, \--noextract*:: - Do not extract source files; use whatever source already exists in the - src/ directory. This is handy if you want to go into src/ and manually - patch or tweak code, then make a package out of the result. Keep in mind - that creating a patch may be a better solution to allow others to use - your PKGBUILD. + Do not extract source files or run the prepare() function (if present); + use whatever source already exists in the $srcdir/ directory. This is + handy if you want to go into $srcdir/ and manually patch or tweak code, + then make a package out of the result. Keep in mind that creating a + patch may be a better solution to allow others to use your PKGBUILD. *-f, \--force*:: makepkg will not build a package if a built package already exists in @@ -116,9 +116,9 @@ Options Disable color in output messages. *-o, \--nobuild*:: - Download and extract files only, but do not build them. Useful with the - '\--noextract' option if you wish to tweak the files in src/ before - building. + Download and extract files, run the prepare() function, but do not build + them. Useful with the '\--noextract' option if you wish to tweak the files + in $srcdir/ before building. *-p* <buildscript>:: Read the package script `buildscript` instead of the `PKGBUILD` default; @@ -152,8 +152,9 @@ Options such as a chroot or remote builder. It will also satisfy requirements of the GPL when distributing binary packages. -*\--pkg <list>*:: - Only build listed packages from a split package. +*\--pkg* <list>:: + Only build listed packages from a split package. Multiple packages should + be comma separated in the list. This option can be specified multiple times. *\--check*:: Run the check() function in the PKGBUILD, overriding the setting in @@ -178,6 +179,10 @@ Options (Passed to pacman) Prevent pacman from waiting for user input before proceeding with operations. +*\--asdeps*:: + (Passed to pacman) Install packages as non-explicitly installed (used + with -i / --install). + *\--noprogressbar*:: (Passed to pacman) Prevent pacman from displaying a progress bar; useful if you are redirecting makepkg output to file. @@ -207,6 +212,10 @@ Environment Variables Folder where the downloaded sources will be stored. Overrides the corresponding value defined in linkman:makepkg.conf[5]. +**PACKAGER=**"John Doe <john@doe.com>":: + String to identify the creator of the resulting package. Overrides + the corresponding value defined in linkman:makepkg.conf[5]. + **BUILDDIR=**"/path/to/folder":: Folder where the package will be built. Overrides the corresponding value defined in linkman:makepkg.conf[5]. diff --git a/doc/makepkg.conf.5.txt b/doc/makepkg.conf.5.txt index db1e6d53..de2b4b42 100644 --- a/doc/makepkg.conf.5.txt +++ b/doc/makepkg.conf.5.txt @@ -51,6 +51,9 @@ Options A string such as ``i686-pc-linux-gnu'', do not touch unless you know what you are doing. This can be commented out by most users if desired. +**CPPFLAGS=**"cppflags":: + Flags used for the C preprocessor; see CFLAGS for more info. + **CFLAGS=**"cflags":: Flags used for the C compiler. This is a key part to the use of makepkg. Usually several options are specified, and the most common string resembles @@ -213,6 +216,10 @@ Options This value is used when querying a package to see who was the builder. It is recommended you change this to your name and email address. +**COMPRESSGZ=**"(gzip -c -f -n)", **COMPRESSBZ2=**"(bzip2 -c -f)", **COMPRESSXZ=**"(xz -c -z -)", **COMPRESSZ=**"(compress -c -f)":: + Sets the command and options used when compressing compiled or source + packages in the named format. + **PKGEXT=**".pkg.tar.gz", **SRCEXT=**".src.tar.gz":: Sets the compression used when making compiled or source packages. The current valid suffixes are `.tar`, `.tar.gz`, `.tar.bz2`, `.tar.xz`, and diff --git a/doc/pacman-key.8.txt b/doc/pacman-key.8.txt index 3631ec8c..8126edb7 100644 --- a/doc/pacman-key.8.txt +++ b/doc/pacman-key.8.txt @@ -12,7 +12,7 @@ pacman-key - manage pacman's list of trusted keys Synopsis -------- -'pacman-key' [options] +'pacman-key' [options] operation [targets] Description @@ -26,45 +26,40 @@ More complex keyring management can be achieved using GnuPG directly combined wi the '\--homedir' option pointing at the pacman keyring (located in +{sysconfdir}/pacman.d/gnupg+ by default). +Invoking pacman-key consists of supplying an operation with any potential +options and targets to operate on. Depending on the operation, a 'target' may +be a valid key identifier, filename, or directory. -Options -------- -*-a, \--add* [file(s)]:: +Operations +---------- +*-a, \--add*:: Add the key(s) contained in the specified file or files to pacman's keyring. If a key already exists, update it. -*\--config* <file>:: - Use an alternate config file instead of the +{sysconfdir}/pacman.conf+ - default. - -*-d, \--delete* <keyid(s)>:: +*-d, \--delete*:: Remove the key(s) identified by the specified keyid(s) from pacman's keyring. -*-e, \--export* [keyid(s)]:: +*-e, \--export*:: Export key(s) identified by the specified keyid(s) to 'stdout'. If no keyid is specified, all keys will be exported. -*\--edit-key* <keyid(s)>:: +*\--edit-key*:: Present a menu for key management task on the specified keyid(s). Useful for adjusting a keys trust level. -*-f, \--finger* [keyid(s)]:: +*-f, \--finger*:: List a fingerprint for each specified keyid, or for all known keys if no keyids are specified. -*\--gpgdir* <dir>:: - Set an alternate home directory for GnuPG. If unspecified, the value is - read from +{sysconfdir}/pacman.conf+. - *-h, \--help*:: Output syntax and command line options. -*\--import* <dir(s)>:: +*\--import*:: Imports keys from `pubring.gpg` into the public keyring from the specified directories. -*\--import-trustdb* <dir(s)> :: +*\--import-trustdb*:: Imports ownertrust values from `trustdb.gpg` into the shared trust database from the specified directories. @@ -72,42 +67,53 @@ Options Ensure the keyring is properly initialized and has the required access permissions. -*\--keyserver* <keyserver>:: - Use the specified keyserver if the operation requires one. This will take - precedence over any keyserver option specified in a `gpg.conf` - configuration file. Running '\--init' with this option will set the default - keyserver if one was not already configured. - -*-l, \--list-keys* [keyid(s)]:: +*-l, \--list-keys*:: Lists all or specified keys from the public keyring. -*\--list-sigs* [keyid(s)]:: +*\--list-sigs*:: Same as '\--list-keys', but the signatures are listed too. -*\--lsign-key* <keyid>:: +*\--lsign-key*:: Locally sign the given key. This is primarily used to root the web of trust in the local private key generated by '\--init'. -*-r, \--recv-keys* <keyid(s)>:: +*-r, \--recv-keys*:: Equivalent to '\--recv-keys' in GnuPG. -*\--refresh-keys* [keyid(s)]:: +*\--refresh-keys*:: Equivalent to '\--refresh-keys' in GnuPG. -*\--populate* [keyring(s)]:: +*\--populate*:: Reload the default keys from the (optionally provided) keyrings in +{pkgdatadir}/keyrings+. For more information, see <<SC,Providing a Keyring for Import>> below. *-u, \--updatedb*:: - Equivalent to '\--check-trustdb' in GnuPG. - -*-v, \--verify* <signature>:: - Verify the given signature file. + Equivalent to '\--check-trustdb' in GnuPG. This operation can be specified with + other operations. *-V, \--version*:: Displays the program version. +*-v, \--verify*:: + Verify the file(s) specified by the signature(s). + +Options +------- +*\--config* <file>:: + Use an alternate config file instead of the +{sysconfdir}/pacman.conf+ + default. + +*\--gpgdir* <dir>:: + Set an alternate home directory for GnuPG. If unspecified, the value is + read from +{sysconfdir}/pacman.conf+. + +*\--keyserver* <keyserver>:: + Use the specified keyserver if the operation requires one. This will take + precedence over any keyserver option specified in a `gpg.conf` + configuration file. Running '\--init' with this option will set the default + keyserver if one was not already configured. + Providing a Keyring for Import ------------------------------ diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt index 62335991..0ad81882 100644 --- a/doc/pacman.8.txt +++ b/doc/pacman.8.txt @@ -70,10 +70,10 @@ Operations In addition to packages, groups can be specified as well. For example, if gnome is a defined package group, then `pacman -S gnome` will provide a prompt allowing you to select which packages to install from a numbered list. -The package selection is specified using a space separated list of package -numbers. Sequential packages may be selected by specifying the first and last -package numbers separated by a hyphen (`-`). Excluding packages is achieved by -prefixing a number or range of numbers with a caret (`^`). +The package selection is specified using a space and/or comma separated list of +package numbers. Sequential packages may be selected by specifying the first +and last package numbers separated by a hyphen (`-`). Excluding packages is +achieved by prefixing a number or range of numbers with a caret (`^`). + Packages that provide other packages are also handled. For example, `pacman -S foo` will first look for a foo package. If foo is not found, packages that @@ -201,7 +201,7 @@ Transaction Options (apply to '-S', '-R' and '-U') Upgrade Options (apply to '-S' and '-U')[[UO]] -------------------------------------------- -*-f, \--force*:: +*\--force*:: Bypass file conflict checks and overwrite conflicting files. If the package that is about to be installed contains files that are already installed, this option will cause all those files to be overwritten. diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt index e793e78b..a9c5db36 100644 --- a/doc/pacman.conf.5.txt +++ b/doc/pacman.conf.5.txt @@ -86,24 +86,17 @@ Options *HoldPkg =* package ...:: If a user tries to '\--remove' a package that's listed in `HoldPkg`, - pacman will ask for confirmation before proceeding. + pacman will ask for confirmation before proceeding. Shell-style glob + patterns are allowed. *IgnorePkg =* package ...:: 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. - *NOTE*: when a `SyncFirst` transaction takes place, no command line flags - (e.g. '\--force') are honored. If this is not ideal, disabling `SyncFirst` - and performing a manual sync of the involved packages may be required. + a '\--sysupgrade'. Shell-style glob patterns are allowed. *IgnoreGroup =* group ...:: Instructs pacman to ignore any upgrades for all packages in this - group when performing a '\--sysupgrade'. + group when performing a '\--sysupgrade'. Shell-style glob patterns are + allowed. *Include =* path:: Include another config file. This file can include repositories or @@ -134,7 +127,8 @@ Options a package install/upgrade, and the new files will be installed with a '.pacnew' extension. These files refer to files in the package archive, so do not include the - leading slash (the RootDir) when specifying them. + leading slash (the RootDir) when specifying them. Shell-style glob patterns + are allowed. *NoExtract =* file ...:: All files listed with a `NoExtract` directive will never be extracted from @@ -143,7 +137,8 @@ Options 'index.php', then you would not want the 'index.html' file to be extracted from the 'apache' package. These files refer to files in the package archive, so do not include the - leading slash (the RootDir) when specifying them. + leading slash (the RootDir) when specifying them. Shell-style glob patterns + are allowed. *CleanMethod =* KeepInstalled &| KeepCurrent:: If set to `KeepInstalled` (the default), the '-Sc' operation will clean @@ -164,9 +159,13 @@ Options Log action messages through syslog(). This will insert log entries into +{localstatedir}/log/messages+ or equivalent. -*UseDelta*:: - Download delta files instead of complete packages if possible. Requires - the xdelta3 program to be installed. +*UseDelta* [= ratio]:: + Download delta files instead of complete packages if possible. Requires + the `xdelta3` program to be installed. If a ratio is specified (e.g., + `0.5`), then it is used as a cutoff for determining whether to use deltas. + Allowed values are between `0.0` and `2.0`; sensible values are between + `0.2` and `0.9`. Using a value above `1.0` is not recommended. The + default is `0.7` if left unspecified. *TotalDownload*:: When downloading, display the amount downloaded, download rate, ETA, diff --git a/doc/pkgdelta.8.txt b/doc/pkgdelta.8.txt index 5913dba6..587320a6 100644 --- a/doc/pkgdelta.8.txt +++ b/doc/pkgdelta.8.txt @@ -35,7 +35,8 @@ Options *--min-pkg-size <size>*:: Minimal size of the package file in bytes to be considered for delta creation. - Default value: 1048576 bytes = 1MiB + Default value: 1048576 bytes = 1MiB. This may be any absolute size in bytes, or + a human readable value such as `4 MiB` or `3.5MB`. *-q, \--quiet*:: Be quiet. Do not output anything but warnings and errors. diff --git a/etc/Makefile.am b/etc/Makefile.am index d504d7fc..58a80bdc 100644 --- a/etc/Makefile.am +++ b/etc/Makefile.am @@ -22,10 +22,9 @@ edit = sed \ -e 's|@ROOTDIR[@]|$(ROOTDIR)|g' $(dist_sysconf_DATA): Makefile - @echo ' ' GEN $@; - @$(RM) $@ $@.tmp - @$(edit) `test -f ./$@.in || echo $(srcdir)/`$@.in >$@.tmp - @mv $@.tmp $@ + $(AM_V_at)$(RM) $@ $@.tmp + $(AM_V_GEN)$(edit) `test -f ./$@.in || echo $(srcdir)/`$@.in >$@.tmp + $(AM_V_at)mv $@.tmp $@ makepkg.conf: $(srcdir)/makepkg.conf.in pacman.conf: $(srcdir)/pacman.conf.in diff --git a/etc/makepkg.conf.in b/etc/makepkg.conf.in index a31a2135..dcec6f5c 100644 --- a/etc/makepkg.conf.in +++ b/etc/makepkg.conf.in @@ -27,6 +27,7 @@ CARCH="@CARCH@" CHOST="@CHOST@" #-- Compiler and Linker Flags +#CPPFLAGS="" #CFLAGS="-O2 -pipe" #CXXFLAGS="-O2 -pipe" #LDFLAGS="" @@ -107,6 +108,16 @@ PURGE_TARGETS=(usr/{,share}/info/dir .packlist *.pod) #GPGKEY="" ######################################################################### +# COMPRESSION DEFAULTS +######################################################################### +# +COMPRESSGZ=(gzip -c -f -n) +COMPRESSBZ2=(bzip2 -c -f) +COMPRESSXZ=(xz -c -z -) +COMPRESSZ=(compress -c -f) + + +######################################################################### # EXTENSION DEFAULTS ######################################################################### # diff --git a/etc/pacman.conf.in b/etc/pacman.conf.in index 932140f4..4c727240 100644 --- a/etc/pacman.conf.in +++ b/etc/pacman.conf.in @@ -15,11 +15,10 @@ #LogFile = @localstatedir@/log/pacman.log #GPGDir = @sysconfdir@/pacman.d/gnupg/ HoldPkg = pacman glibc -# If upgrades are available for these packages they will be asked for first -SyncFirst = pacman #XferCommand = /usr/bin/curl -C - -f %u > %o #XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u #CleanMethod = KeepInstalled +#UseDelta = 0.7 Architecture = auto # Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup @@ -31,7 +30,6 @@ Architecture = auto # Misc options #UseSyslog -#UseDelta #TotalDownload CheckSpace #VerbosePkgLists diff --git a/lib/libalpm/.gitignore b/lib/libalpm/.gitignore index 36d41441..82318d3f 100644 --- a/lib/libalpm/.gitignore +++ b/lib/libalpm/.gitignore @@ -2,3 +2,4 @@ .libs *.lo *.la +libalpm.pc diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am index 99f9c1b7..911e52bf 100644 --- a/lib/libalpm/Makefile.am +++ b/lib/libalpm/Makefile.am @@ -7,7 +7,10 @@ include_HEADERS = alpm_list.h alpm.h DEFS = -DLOCALEDIR=\"@localedir@\" @DEFS@ -AM_CFLAGS = -pedantic -D_GNU_SOURCE +AM_CPPFLAGS = \ + -imacros $(top_builddir)/config.h + +AM_CFLAGS = -pedantic -D_GNU_SOURCE $(WARNING_CFLAGS) if ENABLE_VISIBILITY_CC if DARWIN @@ -20,6 +23,9 @@ if ENABLE_GNU89_INLINE_CC AM_CFLAGS += -fgnu89-inline endif +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libalpm.pc + libalpm_la_SOURCES = \ add.h add.c \ alpm.h alpm.c \ @@ -35,6 +41,7 @@ libalpm_la_SOURCES = \ diskspace.h diskspace.c \ dload.h dload.c \ error.c \ + filelist.h filelist.c \ graph.h graph.c \ group.h group.c \ handle.h handle.c \ @@ -60,7 +67,20 @@ libalpm_la_SOURCES += \ base64.h base64.c endif -libalpm_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_INFO) @LIBCURL@ -libalpm_la_LIBADD = $(LTLIBINTL) +libalpm_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_INFO) + +libalpm_la_CFLAGS = \ + $(AM_CFLAGS) \ + $(GPGME_CFLAGS) \ + $(LIBARCHIVE_CFLAGS) \ + $(LIBCURL_CFLAGS) \ + $(LIBSSL_CFLAGS) + +libalpm_la_LIBADD = \ + $(LTLIBINTL) \ + $(GPGME_LIBS) \ + $(LIBARCHIVE_LIBS) \ + $(LIBCURL_LIBS) \ + $(LIBSSL_LIBS) # vim:set ts=2 sw=2 noet: diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index c49d99b4..edddc318 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -1,7 +1,7 @@ /* * add.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,19 +18,15 @@ * 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 <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> -#include <inttypes.h> /* int64_t */ -#include <stdint.h> /* intmax_t */ +#include <stdint.h> /* int64_t */ /* libarchive */ #include <archive.h> @@ -132,6 +128,18 @@ static int perform_extraction(alpm_handle_t *handle, struct archive *archive, return 0; } +static int try_rename(alpm_handle_t *handle, const char *src, const char *dest) +{ + if(rename(src, dest)) { + _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), + src, dest, strerror(errno)); + alpm_logaction(handle, "error: could not rename %s to %s (%s)\n", + src, dest, strerror(errno)); + return 1; + } + return 0; +} + static int extract_single_file(alpm_handle_t *handle, struct archive *archive, struct archive_entry *entry, alpm_pkg_t *newpkg, alpm_pkg_t *oldpkg) { @@ -146,8 +154,6 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, entryname = archive_entry_pathname(entry); entrymode = archive_entry_mode(entry); - memset(filename, 0, PATH_MAX); /* just to be sure */ - if(strcmp(entryname, ".INSTALL") == 0) { /* the install script goes inside the db */ snprintf(filename, PATH_MAX, "%s%s-%s/install", @@ -170,7 +176,7 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, } /* if a file is in NoExtract then we never extract it */ - if(alpm_list_find_str(handle->noextract, entryname)) { + if(alpm_list_find(handle->noextract, entryname, _alpm_fnmatch)) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoExtract, skipping extraction\n", entryname); alpm_logaction(handle, "note: %s is in NoExtract, skipping extraction\n", @@ -250,7 +256,7 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, } else if(S_ISREG(entrymode)) { /* case 4,7: */ /* if file is in NoUpgrade, don't touch it */ - if(alpm_list_find_str(handle->noupgrade, entryname)) { + if(alpm_list_find(handle->noupgrade, entryname, _alpm_fnmatch)) { notouch = 1; } else { alpm_backup_t *backup; @@ -282,17 +288,18 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, STRDUP(entryname_orig, entryname, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); if(needbackup) { - char checkfile[PATH_MAX]; + char *checkfile; char *hash_local = NULL, *hash_pkg = NULL; - int ret; + size_t len; - snprintf(checkfile, PATH_MAX, "%s.paccheck", filename); + len = strlen(filename) + 10; + MALLOC(checkfile, len, + errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); + snprintf(checkfile, len, "%s.paccheck", filename); - ret = perform_extraction(handle, archive, entry, checkfile, entryname_orig); - if(ret == 1) { - /* error */ - FREE(entryname_orig); - return 1; + if(perform_extraction(handle, archive, entry, checkfile, entryname_orig)) { + errors++; + goto needbackup_cleanup; } hash_local = alpm_compute_md5sum(filename); @@ -320,29 +327,26 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) != 0) { /* looks like we have a local file that has a different hash as the * file in the package, move it to a .pacorig */ - char newpath[PATH_MAX]; - snprintf(newpath, PATH_MAX, "%s.pacorig", filename); + char *newpath; + size_t newlen = strlen(filename) + 9; + MALLOC(newpath, newlen, + errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); + snprintf(newpath, newlen, "%s.pacorig", filename); /* move the existing file to the "pacorig" */ - if(rename(filename, newpath)) { - _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), - filename, newpath, strerror(errno)); - alpm_logaction(handle, "error: could not rename %s to %s (%s)\n", - filename, newpath, strerror(errno)); + if(try_rename(handle, filename, newpath)) { + errors++; errors++; } else { /* rename the file we extracted to the real name */ - if(rename(checkfile, filename)) { - _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), - checkfile, filename, strerror(errno)); - alpm_logaction(handle, "error: could not rename %s to %s (%s)\n", - checkfile, filename, strerror(errno)); + if(try_rename(handle, checkfile, filename)) { errors++; } else { _alpm_log(handle, ALPM_LOG_WARNING, _("%s saved as %s\n"), filename, newpath); alpm_logaction(handle, "warning: %s saved as %s\n", filename, newpath); } } + free(newpath); } else { /* local file is identical to pkg one, so just remove pkg one */ unlink(checkfile); @@ -356,11 +360,7 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n", entryname_orig); - if(rename(checkfile, filename)) { - _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), - checkfile, filename, strerror(errno)); - alpm_logaction(handle, "error: could not rename %s to %s (%s)\n", - checkfile, filename, strerror(errno)); + if(try_rename(handle, checkfile, filename)) { errors++; } } else { @@ -382,29 +382,30 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n"); unlink(checkfile); } else { - char newpath[PATH_MAX]; + char *newpath; + size_t newlen = strlen(filename) + 8; _alpm_log(handle, ALPM_LOG_DEBUG, "action: keeping current file and installing" " new one with .pacnew ending\n"); - snprintf(newpath, PATH_MAX, "%s.pacnew", filename); - if(rename(checkfile, newpath)) { - _alpm_log(handle, ALPM_LOG_ERROR, _("could not install %s as %s (%s)\n"), - filename, newpath, strerror(errno)); - alpm_logaction(handle, "error: could not install %s as %s (%s)\n", - filename, newpath, strerror(errno)); + MALLOC(newpath, newlen, + errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); + snprintf(newpath, newlen, "%s.pacnew", filename); + if(try_rename(handle, checkfile, newpath)) { + errors++; } else { _alpm_log(handle, ALPM_LOG_WARNING, _("%s installed as %s\n"), filename, newpath); alpm_logaction(handle, "warning: %s installed as %s\n", filename, newpath); } + free(newpath); } } - FREE(hash_local); - FREE(hash_pkg); +needbackup_cleanup: + free(checkfile); + free(hash_local); + free(hash_pkg); } else { - int ret; - /* we didn't need a backup */ if(notouch) { /* change the path to a .pacnew extension */ @@ -423,11 +424,11 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, unlink(filename); } - ret = perform_extraction(handle, archive, entry, filename, entryname_orig); - if(ret == 1) { + if(perform_extraction(handle, archive, entry, filename, entryname_orig)) { /* error */ - FREE(entryname_orig); - return 1; + free(entryname_orig); + errors++; + return errors; } /* calculate an hash if this is in newpkg's backup */ @@ -444,7 +445,7 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, backup->hash = newhash; } } - FREE(entryname_orig); + free(entryname_orig); return errors; } @@ -522,31 +523,20 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg, if(!(trans->flags & ALPM_TRANS_FLAG_DBONLY)) { struct archive *archive; struct archive_entry *entry; - int cwdfd; + struct stat buf; + int fd, cwdfd; _alpm_log(handle, ALPM_LOG_DEBUG, "extracting files\n"); - if((archive = archive_read_new()) == NULL) { - handle->pm_errno = ALPM_ERR_LIBARCHIVE; - ret = -1; - goto cleanup; - } - - archive_read_support_compression_all(archive); - archive_read_support_format_all(archive); - - _alpm_log(handle, ALPM_LOG_DEBUG, "archive: %s\n", pkgfile); - if(archive_read_open_filename(archive, pkgfile, - ALPM_BUFFER_SIZE) != ARCHIVE_OK) { - handle->pm_errno = ALPM_ERR_PKG_OPEN; + fd = _alpm_open_archive(db->handle, pkgfile, &buf, + &archive, ALPM_ERR_PKG_OPEN); + if(fd < 0) { ret = -1; goto cleanup; } /* save the cwd so we can restore it later */ - do { - cwdfd = open(".", O_RDONLY); - } while(cwdfd == -1 && errno == EINTR); + OPEN(cwdfd, ".", O_RDONLY); if(cwdfd < 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n")); } @@ -555,6 +545,8 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg, if(chdir(handle->root) != 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"), handle->root, strerror(errno)); + archive_read_finish(archive); + CLOSE(fd); ret = -1; goto cleanup; } @@ -596,6 +588,7 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg, errors += extract_single_file(handle, archive, entry, newpkg, oldpkg); } archive_read_finish(archive); + CLOSE(fd); /* restore the old cwd if we have it */ if(cwdfd >= 0) { @@ -603,7 +596,7 @@ static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg, _alpm_log(handle, ALPM_LOG_ERROR, _("could not restore working directory (%s)\n"), strerror(errno)); } - close(cwdfd); + CLOSE(cwdfd); } if(errors) { diff --git a/lib/libalpm/add.h b/lib/libalpm/add.h index 77a3d22a..d1368e8a 100644 --- a/lib/libalpm/add.h +++ b/lib/libalpm/add.h @@ -1,7 +1,7 @@ /* * add.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify diff --git a/lib/libalpm/alpm.c b/lib/libalpm/alpm.c index 38843342..c58a4069 100644 --- a/lib/libalpm/alpm.c +++ b/lib/libalpm/alpm.c @@ -1,7 +1,7 @@ /* * alpm.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -21,8 +21,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #ifdef HAVE_LIBCURL #include <curl/curl.h> #endif @@ -47,9 +45,9 @@ * @return a context handle on success, NULL on error, err will be set if provided */ alpm_handle_t SYMEXPORT *alpm_initialize(const char *root, const char *dbpath, - enum _alpm_errno_t *err) + alpm_errno_t *err) { - enum _alpm_errno_t myerr; + alpm_errno_t myerr; const char *lf = "db.lck"; size_t lockfilelen; alpm_handle_t *myhandle = _alpm_handle_new(); @@ -108,7 +106,7 @@ int SYMEXPORT alpm_release(alpm_handle_t *myhandle) myhandle->db_local = NULL; } - if(alpm_db_unregister_all(myhandle) == -1) { + if(alpm_unregister_all_syncdbs(myhandle) == -1) { ret = -1; } diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 6df3e1f5..1d6a8c6c 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -1,7 +1,7 @@ /* * alpm.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -27,14 +27,12 @@ extern "C" { #endif -#include <sys/types.h> /* for off_t */ -#include <time.h> /* for time_t */ -#include <stdarg.h> /* for va_list */ +#include <stdint.h> /* int64_t */ +#include <sys/types.h> /* off_t */ +#include <stdarg.h> /* va_list */ #include <alpm_list.h> -#define DEPRECATED __attribute__((deprecated)) - /* * Arch Linux Package Management library */ @@ -44,15 +42,14 @@ extern "C" { * @{ */ +typedef int64_t alpm_time_t; + /* * Enumerations * These ones are used in multiple contexts, so are forward-declared. */ -/** - * Install reasons. - * Why the package was installed. - */ +/** Package install reasons. */ typedef enum _alpm_pkgreason_t { /** Explicitly requested by the user. */ ALPM_PKG_REASON_EXPLICIT = 0, @@ -60,12 +57,22 @@ typedef enum _alpm_pkgreason_t { ALPM_PKG_REASON_DEPEND = 1 } alpm_pkgreason_t; +/** Location a package object was loaded from. */ typedef enum _alpm_pkgfrom_t { - PKG_FROM_FILE = 1, - PKG_FROM_LOCALDB, - PKG_FROM_SYNCDB + ALPM_PKG_FROM_FILE = 1, + ALPM_PKG_FROM_LOCALDB, + ALPM_PKG_FROM_SYNCDB } alpm_pkgfrom_t; +/** Location a package object was loaded from. */ +typedef enum _alpm_pkgvalidation_t { + ALPM_PKG_VALIDATION_UNKNOWN = 0, + ALPM_PKG_VALIDATION_NONE = (1 << 0), + ALPM_PKG_VALIDATION_MD5SUM = (1 << 1), + ALPM_PKG_VALIDATION_SHA256SUM = (1 << 2), + ALPM_PKG_VALIDATION_SIGNATURE = (1 << 3) +} alpm_pkgvalidation_t; + /** Types of version constraints in dependency specs. */ typedef enum _alpm_depmod_t { /** No version constraint */ @@ -92,9 +99,7 @@ typedef enum _alpm_fileconflicttype_t { ALPM_FILECONFLICT_FILESYSTEM } alpm_fileconflicttype_t; -/** - * PGP signature verification options - */ +/** PGP signature verification options */ typedef enum _alpm_siglevel_t { ALPM_SIG_PACKAGE = (1 << 0), ALPM_SIG_PACKAGE_OPTIONAL = (1 << 1), @@ -109,9 +114,7 @@ typedef enum _alpm_siglevel_t { ALPM_SIG_USE_DEFAULT = (1 << 31) } alpm_siglevel_t; -/** - * PGP signature verification status return codes - */ +/** PGP signature verification status return codes */ typedef enum _alpm_sigstatus_t { ALPM_SIGSTATUS_VALID, ALPM_SIGSTATUS_KEY_EXPIRED, @@ -121,9 +124,7 @@ typedef enum _alpm_sigstatus_t { ALPM_SIGSTATUS_INVALID } alpm_sigstatus_t; -/** - * PGP signature verification status return codes - */ +/** PGP signature verification status return codes */ typedef enum _alpm_sigvalidity_t { ALPM_SIGVALIDITY_FULL, ALPM_SIGVALIDITY_MARGINAL, @@ -144,6 +145,7 @@ typedef struct __alpm_trans_t alpm_trans_t; typedef struct _alpm_depend_t { char *name; char *version; + char *desc; unsigned long name_hash; alpm_depmod_t mod; } alpm_depend_t; @@ -152,7 +154,7 @@ typedef struct _alpm_depend_t { typedef struct _alpm_depmissing_t { char *target; alpm_depend_t *depend; - /* this is used in case of remove dependency error only */ + /* this is used only in the case of a remove dependency error */ char *causingpkg; } alpm_depmissing_t; @@ -222,11 +224,15 @@ typedef struct _alpm_pgpkey_t { char *uid; char *name; char *email; - time_t created; - time_t expires; + alpm_time_t created; + alpm_time_t expires; + unsigned int length; + unsigned int revoked; + char pubkey_algo; } alpm_pgpkey_t; -/** Signature result. Contains the key, status, and validity of a given +/** + * Signature result. Contains the key, status, and validity of a given * signature. */ typedef struct _alpm_sigresult_t { @@ -235,7 +241,8 @@ typedef struct _alpm_sigresult_t { alpm_sigvalidity_t validity; } alpm_sigresult_t; -/** Signature list. Contains the number of signatures found and a pointer to an +/** + * Signature list. Contains the number of signatures found and a pointer to an * array of results. The array is of size count. */ typedef struct _alpm_siglist_t { @@ -247,9 +254,7 @@ typedef struct _alpm_siglist_t { * Logging facilities */ -/** - * Logging Levels - */ +/** Logging Levels */ typedef enum _alpm_loglevel_t { ALPM_LOG_ERROR = 1, ALPM_LOG_WARNING = (1 << 1), @@ -260,7 +265,8 @@ typedef enum _alpm_loglevel_t { typedef void (*alpm_cb_log)(alpm_loglevel_t, const char *, va_list); int alpm_logaction(alpm_handle_t *handle, const char *fmt, ...); -/** Events. +/** + * Events. * NULL parameters are passed to in all events unless specified otherwise. */ typedef enum _alpm_event_t { @@ -341,13 +347,18 @@ typedef enum _alpm_event_t { /** Disk space usage will be computed for a package */ ALPM_EVENT_DISKSPACE_START, /** Disk space usage was computed for a package */ - ALPM_EVENT_DISKSPACE_DONE, + ALPM_EVENT_DISKSPACE_DONE } alpm_event_t; /** Event callback */ typedef void (*alpm_cb_event)(alpm_event_t, void *, void *); -/** Questions */ +/** + * Questions. + * Unlike the events or progress enumerations, this enum has bitmask values + * so a frontend can use a bitmask map to supply preselected answers to the + * different types of questions. + */ typedef enum _alpm_question_t { ALPM_QUESTION_INSTALL_IGNOREPKG = 1, ALPM_QUESTION_REPLACE_PKG = (1 << 1), @@ -370,7 +381,7 @@ typedef enum _alpm_progress_t { ALPM_PROGRESS_CONFLICTS_START, ALPM_PROGRESS_DISKSPACE_START, ALPM_PROGRESS_INTEGRITY_START, - ALPM_PROGRESS_LOAD_START, + ALPM_PROGRESS_LOAD_START } alpm_progress_t; /** Progress callback */ @@ -530,8 +541,8 @@ const char *alpm_option_get_arch(alpm_handle_t *handle); /** Sets the targeted architecture. */ int alpm_option_set_arch(alpm_handle_t *handle, const char *arch); -int alpm_option_get_usedelta(alpm_handle_t *handle); -int alpm_option_set_usedelta(alpm_handle_t *handle, int usedelta); +double alpm_option_get_deltaratio(alpm_handle_t *handle); +int alpm_option_set_deltaratio(alpm_handle_t *handle, double ratio); int alpm_option_get_checkspace(alpm_handle_t *handle); int alpm_option_set_checkspace(alpm_handle_t *handle, int checkspace); @@ -552,7 +563,7 @@ int alpm_option_set_default_siglevel(alpm_handle_t *handle, alpm_siglevel_t leve * libalpm functions. * @return a reference to the local database */ -alpm_db_t *alpm_option_get_localdb(alpm_handle_t *handle); +alpm_db_t *alpm_get_localdb(alpm_handle_t *handle); /** Get the list of sync databases. * Returns a list of alpm_db_t structures, one for each registered @@ -560,7 +571,7 @@ alpm_db_t *alpm_option_get_localdb(alpm_handle_t *handle); * @param handle the context handle * @return a reference to an internal list of alpm_db_t structures */ -alpm_list_t *alpm_option_get_syncdbs(alpm_handle_t *handle); +alpm_list_t *alpm_get_syncdbs(alpm_handle_t *handle); /** Register a sync database of packages. * @param handle the context handle @@ -569,20 +580,20 @@ alpm_list_t *alpm_option_get_syncdbs(alpm_handle_t *handle); * database; note that this must be a '.sig' file type verification * @return an alpm_db_t* on success (the value), NULL on error */ -alpm_db_t *alpm_db_register_sync(alpm_handle_t *handle, const char *treename, +alpm_db_t *alpm_register_syncdb(alpm_handle_t *handle, const char *treename, alpm_siglevel_t level); -/** Unregister a package database. - * @param db pointer to the package database to unregister +/** Unregister all package databases. + * @param handle the context handle * @return 0 on success, -1 on error (pm_errno is set accordingly) */ -int alpm_db_unregister(alpm_db_t *db); +int alpm_unregister_all_syncdbs(alpm_handle_t *handle); -/** Unregister all package databases. - * @param handle the context handle +/** Unregister a package database. + * @param db pointer to the package database to unregister * @return 0 on success, -1 on error (pm_errno is set accordingly) */ -int alpm_db_unregister_all(alpm_handle_t *handle); +int alpm_db_unregister(alpm_db_t *db); /** Get the name of a package database. * @param db pointer to the package database @@ -615,7 +626,7 @@ int alpm_db_add_server(alpm_db_t *db, const char *url); int alpm_db_remove_server(alpm_db_t *db, const char *url); /** @} */ -int alpm_db_update(int level, alpm_db_t *db); +int alpm_db_update(int force, alpm_db_t *db); /** Get a package entry from a package database. * @param db pointer to the package database to get the package from @@ -635,7 +646,7 @@ alpm_list_t *alpm_db_get_pkgcache(alpm_db_t *db); * @param name of the group * @return the groups entry on success, NULL on error */ -alpm_group_t *alpm_db_readgroup(alpm_db_t *db, const char *name); +alpm_group_t *alpm_db_get_group(alpm_db_t *db, const char *name); /** Get the group cache of a package database. * @param db pointer to the package database to get the group from @@ -648,16 +659,7 @@ alpm_list_t *alpm_db_get_groupcache(alpm_db_t *db); * @param needles a list of regular expressions to search for * @return the list of packages matching all regular expressions on success, NULL on error */ -alpm_list_t *alpm_db_search(alpm_db_t *db, const alpm_list_t* needles); - -/** Set install reason for a package in db. - * @param handle the context handle - * @param pkg the package to update - * @param reason the new install reason - * @return 0 on success, -1 on error (pm_errno is set accordingly) - */ -int alpm_db_set_pkgreason(alpm_handle_t *handle, alpm_pkg_t *pkg, - alpm_pkgreason_t reason); +alpm_list_t *alpm_db_search(alpm_db_t *db, const alpm_list_t *needles); /** @} */ @@ -754,13 +756,13 @@ const char *alpm_pkg_get_url(alpm_pkg_t *pkg); * @param pkg a pointer to package * @return the timestamp of the build time */ -time_t alpm_pkg_get_builddate(alpm_pkg_t *pkg); +alpm_time_t alpm_pkg_get_builddate(alpm_pkg_t *pkg); /** Returns the install timestamp of the package. * @param pkg a pointer to package * @return the timestamp of the install time */ -time_t alpm_pkg_get_installdate(alpm_pkg_t *pkg); +alpm_time_t alpm_pkg_get_installdate(alpm_pkg_t *pkg); /** Returns the packager's name. * @param pkg a pointer to package @@ -827,7 +829,7 @@ alpm_list_t *alpm_pkg_get_depends(alpm_pkg_t *pkg); /** Returns the list of package optional dependencies. * @param pkg a pointer to package - * @return a reference to an internal list of strings. + * @return a reference to an internal list of alpm_depend_t structures. */ alpm_list_t *alpm_pkg_get_optdepends(alpm_pkg_t *pkg); @@ -869,7 +871,7 @@ alpm_filelist_t *alpm_pkg_get_files(alpm_pkg_t *pkg); * "<filename>\t<md5sum>", where the given md5sum is that of * the file as provided by the package. * @param pkg a pointer to package - * @return a reference to an internal list of strings. + * @return a reference to a list of alpm_backup_t objects */ alpm_list_t *alpm_pkg_get_backup(alpm_pkg_t *pkg); @@ -887,6 +889,12 @@ alpm_db_t *alpm_pkg_get_db(alpm_pkg_t *pkg); */ const char *alpm_pkg_get_base64_sig(alpm_pkg_t *pkg); +/** Returns the method used to validate a package during install. + * @param pkg a pointer to package + * @return an enum member giving the validation method + */ +alpm_pkgvalidation_t alpm_pkg_get_validation(alpm_pkg_t *pkg); + /* End of alpm_pkg_t accessors */ /* @} */ @@ -928,10 +936,34 @@ off_t alpm_pkg_download_size(alpm_pkg_t *newpkg); alpm_list_t *alpm_pkg_unused_deltas(alpm_pkg_t *pkg); +/** Set install reason for a package in the local database. + * The provided package object must be from the local database or this method + * will fail. The write to the local database is performed immediately. + * @param pkg the package to update + * @param reason the new install reason + * @return 0 on success, -1 on error (pm_errno is set accordingly) + */ +int alpm_pkg_set_reason(alpm_pkg_t *pkg, alpm_pkgreason_t reason); + + /* End of alpm_pkg */ /** @} */ /* + * Filelists + */ + +/** Determines whether a package filelist contains a given path. + * The provided path should be relative to the install root with no leading + * slashes, e.g. "etc/localtime". When searching for directories, the path must + * have a trailing slash. + * @param filelist a pointer to a package filelist + * @param path the path to search for in the package + * @return a pointer to the matching file or NULL if not found + */ +alpm_file_t *alpm_filelist_contains(alpm_filelist_t *filelist, const char *path); + +/* * Signatures */ @@ -1107,13 +1139,13 @@ char *alpm_dep_compute_string(const alpm_depend_t *dep); */ /* checksums */ -char *alpm_compute_md5sum(const char *name); +char *alpm_compute_md5sum(const char *filename); char *alpm_compute_sha256sum(const char *filename); /** @addtogroup alpm_api_errors Error Codes * @{ */ -enum _alpm_errno_t { +typedef enum _alpm_errno_t { ALPM_ERR_MEMORY = 1, ALPM_ERR_SYSTEM, ALPM_ERR_BADPERMS, @@ -1177,19 +1209,19 @@ enum _alpm_errno_t { ALPM_ERR_LIBCURL, ALPM_ERR_EXTERNAL_DOWNLOAD, ALPM_ERR_GPGME -}; +} alpm_errno_t; /** Returns the current error code from the handle. */ -enum _alpm_errno_t alpm_errno(alpm_handle_t *handle); +alpm_errno_t alpm_errno(alpm_handle_t *handle); /** Returns the string corresponding to an error number. */ -const char *alpm_strerror(enum _alpm_errno_t err); +const char *alpm_strerror(alpm_errno_t err); /* End of alpm_api_errors */ /** @} */ alpm_handle_t *alpm_initialize(const char *root, const char *dbpath, - enum _alpm_errno_t *err); + alpm_errno_t *err); int alpm_release(alpm_handle_t *handle); enum alpm_caps { diff --git a/lib/libalpm/alpm_list.c b/lib/libalpm/alpm_list.c index 3aa4f9bc..39eded13 100644 --- a/lib/libalpm/alpm_list.c +++ b/lib/libalpm/alpm_list.c @@ -1,7 +1,7 @@ /* * alpm_list.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -204,7 +204,8 @@ alpm_list_t SYMEXPORT *alpm_list_join(alpm_list_t *first, alpm_list_t *second) * * @return the resultant list */ -alpm_list_t SYMEXPORT *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right, alpm_list_fn_cmp fn) +alpm_list_t SYMEXPORT *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right, + alpm_list_fn_cmp fn) { alpm_list_t *newlist, *lp, *tail_ptr, *left_tail_ptr, *right_tail_ptr; @@ -273,20 +274,26 @@ alpm_list_t SYMEXPORT *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right, a * * @return the resultant list */ -alpm_list_t SYMEXPORT *alpm_list_msort(alpm_list_t *list, size_t n, alpm_list_fn_cmp fn) +alpm_list_t SYMEXPORT *alpm_list_msort(alpm_list_t *list, size_t n, + alpm_list_fn_cmp fn) { if(n > 1) { - alpm_list_t *left = list; - alpm_list_t *lastleft = alpm_list_nth(list, n/2 - 1); - alpm_list_t *right = lastleft->next; + size_t half = n / 2; + size_t i = half - 1; + alpm_list_t *left = list, *lastleft = list, *right; + + while(i--) { + lastleft = lastleft->next; + } + right = lastleft->next; /* tidy new lists */ lastleft->next = NULL; right->prev = left->prev; left->prev = lastleft; - left = alpm_list_msort(left, n/2, fn); - right = alpm_list_msort(right, n - (n/2), fn); + left = alpm_list_msort(left, half, fn); + right = alpm_list_msort(right, n - half, fn); list = alpm_list_mmerge(left, right, fn); } return list; @@ -579,19 +586,6 @@ alpm_list_t SYMEXPORT *alpm_list_last(const alpm_list_t *list) } } -/** - * @brief Get the data member of a list node. - * - * @param node the list node - * - * @return the contained data, or NULL if none - */ -void SYMEXPORT *alpm_list_getdata(const alpm_list_t *node) -{ - if(node == NULL) return NULL; - return node->data; -} - /* Misc */ /** diff --git a/lib/libalpm/alpm_list.h b/lib/libalpm/alpm_list.h index cd7b0291..8f743a28 100644 --- a/lib/libalpm/alpm_list.h +++ b/lib/libalpm/alpm_list.h @@ -1,7 +1,7 @@ /* * alpm_list.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -71,7 +71,6 @@ alpm_list_t *alpm_list_nth(const alpm_list_t *list, size_t n); alpm_list_t *alpm_list_next(const alpm_list_t *list); alpm_list_t *alpm_list_previous(const alpm_list_t *list); alpm_list_t *alpm_list_last(const alpm_list_t *list); -void *alpm_list_getdata(const alpm_list_t *entry); /* misc */ size_t alpm_list_count(const alpm_list_t *list); diff --git a/lib/libalpm/backup.c b/lib/libalpm/backup.c index 728c1d05..98b5f5e3 100644 --- a/lib/libalpm/backup.c +++ b/lib/libalpm/backup.c @@ -1,7 +1,7 @@ /* * backup.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2005 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -21,8 +21,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <string.h> diff --git a/lib/libalpm/backup.h b/lib/libalpm/backup.h index 0b84a68c..c539406d 100644 --- a/lib/libalpm/backup.h +++ b/lib/libalpm/backup.h @@ -1,7 +1,7 @@ /* * backup.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify diff --git a/lib/libalpm/base64.c b/lib/libalpm/base64.c index 5c9fa814..32c44459 100644 --- a/lib/libalpm/base64.c +++ b/lib/libalpm/base64.c @@ -32,6 +32,8 @@ * * removal of SELF_TEST code */ +#include <stdint.h> + #include "base64.h" static const unsigned char base64_enc_map[64] = @@ -62,6 +64,7 @@ static const unsigned char base64_dec_map[128] = 49, 50, 51, 127, 127, 127, 127, 127 }; +#if 0 /* * Encode a buffer into base64 format */ @@ -124,6 +127,7 @@ int base64_encode( unsigned char *dst, size_t *dlen, return( 0 ); } +#endif /* * Decode a base64-formatted buffer @@ -131,8 +135,8 @@ int base64_encode( unsigned char *dst, size_t *dlen, int base64_decode( unsigned char *dst, size_t *dlen, const unsigned char *src, size_t slen ) { - size_t i, j, n; - unsigned long x; + size_t i, n; + uint32_t j, x; unsigned char *p; for( i = j = n = 0; i < slen; i++ ) diff --git a/lib/libalpm/base64.h b/lib/libalpm/base64.h index 406aefa1..df684ab7 100644 --- a/lib/libalpm/base64.h +++ b/lib/libalpm/base64.h @@ -30,6 +30,7 @@ #define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL -0x0010 /**< Output buffer too small. */ #define POLARSSL_ERR_BASE64_INVALID_CHARACTER -0x0012 /**< Invalid character in input. */ +#if 0 /** * \brief Encode a buffer into base64 format * @@ -47,6 +48,7 @@ */ int base64_encode( unsigned char *dst, size_t *dlen, const unsigned char *src, size_t slen ); +#endif /** * \brief Decode a base64-formatted buffer diff --git a/lib/libalpm/be_local.c b/lib/libalpm/be_local.c index 56cf38bb..bbc0a8ac 100644 --- a/lib/libalpm/be_local.c +++ b/lib/libalpm/be_local.c @@ -1,7 +1,7 @@ /* * be_local.c : backend for the local database * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <unistd.h> #include <stdio.h> #include <stdlib.h> @@ -28,7 +26,6 @@ #include <stdint.h> /* intmax_t */ #include <sys/stat.h> #include <dirent.h> -#include <time.h> #include <limits.h> /* PATH_MAX */ /* libalpm */ @@ -40,6 +37,7 @@ #include "handle.h" #include "package.h" #include "deps.h" +#include "filelist.h" static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq); @@ -69,13 +67,13 @@ static const char *_cache_get_url(alpm_pkg_t *pkg) return pkg->url; } -static time_t _cache_get_builddate(alpm_pkg_t *pkg) +static alpm_time_t _cache_get_builddate(alpm_pkg_t *pkg) { LAZY_LOAD(INFRQ_DESC, 0); return pkg->builddate; } -static time_t _cache_get_installdate(alpm_pkg_t *pkg) +static alpm_time_t _cache_get_installdate(alpm_pkg_t *pkg) { LAZY_LOAD(INFRQ_DESC, 0); return pkg->installdate; @@ -105,6 +103,12 @@ static alpm_pkgreason_t _cache_get_reason(alpm_pkg_t *pkg) return pkg->reason; } +static alpm_pkgvalidation_t _cache_get_validation(alpm_pkg_t *pkg) +{ + LAZY_LOAD(INFRQ_DESC, -1); + return pkg->validation; +} + static alpm_list_t *_cache_get_licenses(alpm_pkg_t *pkg) { LAZY_LOAD(INFRQ_DESC, NULL); @@ -226,6 +230,7 @@ static struct pkg_operations local_pkg_ops = { .get_arch = _cache_get_arch, .get_isize = _cache_get_isize, .get_reason = _cache_get_reason, + .get_validation = _cache_get_validation, .has_scriptlet = _cache_has_scriptlet, .get_licenses = _cache_get_licenses, .get_groups = _cache_get_groups, @@ -401,12 +406,11 @@ static int local_db_populate(alpm_db_t *db) rewinddir(dbdir); } if(est_count >= 2) { - /* subtract the two extra pointers to get # of children */ + /* subtract the '.' and '..' pointers to get # of children */ est_count -= 2; } - /* initialize hash at 50% full */ - db->pkgcache = _alpm_pkghash_create(est_count * 2); + db->pkgcache = _alpm_pkghash_create(est_count); if(db->pkgcache == NULL){ closedir(dbdir); RET_ERR(db->handle, ALPM_ERR_MEMORY, -1); @@ -445,7 +449,7 @@ static int local_db_populate(alpm_db_t *db) continue; } - pkg->origin = PKG_FROM_LOCALDB; + pkg->origin = ALPM_PKG_FROM_LOCALDB; pkg->origin_data.db = db; pkg->ops = &local_pkg_ops; pkg->handle = db->handle; @@ -475,7 +479,8 @@ static int local_db_populate(alpm_db_t *db) } /* Note: the return value must be freed by the caller */ -char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info, const char *filename) +char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info, + const char *filename) { size_t len; char *pkgpath; @@ -492,7 +497,7 @@ char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info, const char *filena #define READ_NEXT() do { \ if(fgets(line, sizeof(line), fp) == NULL && !feof(fp)) goto error; \ - _alpm_strip_newline(line); \ + _alpm_strip_newline(line, 0); \ } while(0) #define READ_AND_STORE(f) do { \ @@ -505,7 +510,7 @@ char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info, const char *filena if(fgets(line, sizeof(line), fp) == NULL) {\ if(!feof(fp)) goto error; else break; \ } \ - if(_alpm_strip_newline(line) == 0) break; \ + if(_alpm_strip_newline(line, 0) == 0) break; \ STRDUP(linedup, line, goto error); \ f = alpm_list_add(f, linedup); \ } while(1) /* note the while(1) and not (0) */ @@ -514,7 +519,7 @@ char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info, const char *filena if(fgets(line, sizeof(line), fp) == NULL) {\ if(!feof(fp)) goto error; else break; \ } \ - if(_alpm_strip_newline(line) == 0) break; \ + if(_alpm_strip_newline(line, 0) == 0) break; \ f = alpm_list_add(f, _alpm_splitdep(line)); \ } while(1) /* note the while(1) and not (0) */ @@ -522,7 +527,6 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) { FILE *fp = NULL; char line[1024]; - char *pkgpath; alpm_db_t *db = info->origin_data.db; /* bitmask logic here: @@ -541,18 +545,10 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) return -1; } - _alpm_log(db->handle, ALPM_LOG_FUNCTION, "loading package data for %s : level=0x%x\n", + _alpm_log(db->handle, ALPM_LOG_FUNCTION, + "loading package data for %s : level=0x%x\n", info->name, inforeq); - pkgpath = _alpm_local_db_pkgpath(db, info, NULL); - if(!pkgpath || access(pkgpath, F_OK)) { - /* directory doesn't exist or can't be opened */ - _alpm_log(db->handle, ALPM_LOG_DEBUG, "cannot find '%s-%s' in db '%s'\n", - info->name, info->version, db->treename); - goto error; - } - free(pkgpath); - /* clear out 'line', to be certain - and to make valgrind happy */ memset(line, 0, sizeof(line)); @@ -569,7 +565,7 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) if(fgets(line, sizeof(line), fp) == NULL && !feof(fp)) { goto error; } - if(_alpm_strip_newline(line) == 0) { + if(_alpm_strip_newline(line, 0) == 0) { /* length of stripped line was zero */ continue; } @@ -606,6 +602,26 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) } else if(strcmp(line, "%REASON%") == 0) { READ_NEXT(); info->reason = (alpm_pkgreason_t)atoi(line); + } else if(strcmp(line, "%VALIDATION%") == 0) { + alpm_list_t *i, *v = NULL; + READ_AND_STORE_ALL(v); + for(i = v; i; i = alpm_list_next(i)) + { + if(strcmp(i->data, "none") == 0) { + info->validation |= ALPM_PKG_VALIDATION_NONE; + } else if(strcmp(i->data, "md5") == 0) { + info->validation |= ALPM_PKG_VALIDATION_MD5SUM; + } else if(strcmp(i->data, "sha256") == 0) { + info->validation |= ALPM_PKG_VALIDATION_SHA256SUM; + } else if(strcmp(i->data, "pgp") == 0) { + info->validation |= ALPM_PKG_VALIDATION_SIGNATURE; + } else { + _alpm_log(db->handle, ALPM_LOG_WARNING, + _("unknown validation type for package %s: %s\n"), + info->name, (const char *)i->data); + } + } + FREELIST(v); } else if(strcmp(line, "%SIZE%") == 0) { READ_NEXT(); info->isize = _alpm_strtoofft(line); @@ -614,7 +630,7 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) } else if(strcmp(line, "%DEPENDS%") == 0) { READ_AND_SPLITDEP(info->depends); } else if(strcmp(line, "%OPTDEPENDS%") == 0) { - READ_AND_STORE_ALL(info->optdepends); + READ_AND_SPLITDEP(info->optdepends); } else if(strcmp(line, "%CONFLICTS%") == 0) { READ_AND_SPLITDEP(info->conflicts); } else if(strcmp(line, "%PROVIDES%") == 0) { @@ -636,12 +652,13 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) } free(path); while(fgets(line, sizeof(line), fp)) { - _alpm_strip_newline(line); + _alpm_strip_newline(line, 0); if(strcmp(line, "%FILES%") == 0) { - size_t files_count = 0, files_size = 0; + size_t files_count = 0, files_size = 0, len; alpm_file_t *files = NULL; - while(fgets(line, sizeof(line), fp) && _alpm_strip_newline(line)) { + while(fgets(line, sizeof(line), fp) && + (len = _alpm_strip_newline(line, 0))) { if(files_count >= files_size) { size_t old_size = files_size; if(files_size == 0) { @@ -651,7 +668,7 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) } files = realloc(files, sizeof(alpm_file_t) * files_size); if(!files) { - ALLOC_FAIL(sizeof(alpm_file_t) * files_size); + _alpm_alloc_fail(sizeof(alpm_file_t) * files_size); goto error; } /* ensure all new memory is zeroed out, in both the initial @@ -659,16 +676,25 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) memset(files + old_size, 0, sizeof(alpm_file_t) * (files_size - old_size)); } - STRDUP(files[files_count].name, line, goto error); - /* TODO: lstat file, get mode/size */ + /* since we know the length of the file string already, + * we can do malloc + memcpy rather than strdup */ + len += 1; + files[files_count].name = malloc(len); + if(files[files_count].name == NULL) { + _alpm_alloc_fail(len); + goto error; + } + memcpy(files[files_count].name, line, len); files_count++; } /* attempt to hand back any memory we don't need */ files = realloc(files, sizeof(alpm_file_t) * files_count); + /* make sure the list is sorted */ + qsort(files, files_count, sizeof(alpm_file_t), _alpm_files_cmp); info->files.count = files_count; info->files.files = files; } else if(strcmp(line, "%BACKUP%") == 0) { - while(fgets(line, sizeof(line), fp) && _alpm_strip_newline(line)) { + while(fgets(line, sizeof(line), fp) && _alpm_strip_newline(line, 0)) { alpm_backup_t *backup; CALLOC(backup, 1, sizeof(alpm_backup_t), goto error); if(_alpm_split_backup(line, &backup)) { @@ -727,6 +753,23 @@ int _alpm_local_db_prepare(alpm_db_t *db, alpm_pkg_t *info) return retval; } +static void write_deps(FILE *fp, const char *header, alpm_list_t *deplist) +{ + alpm_list_t *lp; + if(!deplist) { + return; + } + fputs(header, fp); + fputc('\n', fp); + for(lp = deplist; lp; lp = lp->next) { + char *depstring = alpm_dep_compute_string(lp->data); + fputs(depstring, fp); + fputc('\n', fp); + free(depstring); + } + fputc('\n', fp); +} + int _alpm_local_db_write(alpm_db_t *db, alpm_pkg_t *info, alpm_dbinfrq_t inforeq) { FILE *fp = NULL; @@ -744,7 +787,8 @@ int _alpm_local_db_write(alpm_db_t *db, alpm_pkg_t *info, alpm_dbinfrq_t inforeq /* DESC */ if(inforeq & INFRQ_DESC) { char *path; - _alpm_log(db->handle, ALPM_LOG_DEBUG, "writing %s-%s DESC information back to db\n", + _alpm_log(db->handle, ALPM_LOG_DEBUG, + "writing %s-%s DESC information back to db\n", info->name, info->version); path = _alpm_local_db_pkgpath(db, info, "desc"); if(!path || (fp = fopen(path, "w")) == NULL) { @@ -761,44 +805,21 @@ int _alpm_local_db_write(alpm_db_t *db, alpm_pkg_t *info, alpm_dbinfrq_t inforeq fprintf(fp, "%%DESC%%\n" "%s\n\n", info->desc); } - if(info->groups) { - fputs("%GROUPS%\n", fp); - for(lp = info->groups; lp; lp = lp->next) { - fprintf(fp, "%s\n", (char *)lp->data); - } - fprintf(fp, "\n"); - } - if(info->replaces) { - fputs("%REPLACES%\n", fp); - for(lp = info->replaces; lp; lp = lp->next) { - char *depstring = alpm_dep_compute_string(lp->data); - fprintf(fp, "%s\n", depstring); - free(depstring); - } - fprintf(fp, "\n"); - } if(info->url) { fprintf(fp, "%%URL%%\n" "%s\n\n", info->url); } - if(info->licenses) { - fputs("%LICENSE%\n", fp); - for(lp = info->licenses; lp; lp = lp->next) { - fprintf(fp, "%s\n", (char *)lp->data); - } - fprintf(fp, "\n"); - } if(info->arch) { fprintf(fp, "%%ARCH%%\n" "%s\n\n", info->arch); } if(info->builddate) { fprintf(fp, "%%BUILDDATE%%\n" - "%ld\n\n", info->builddate); + "%jd\n\n", (intmax_t)info->builddate); } if(info->installdate) { fprintf(fp, "%%INSTALLDATE%%\n" - "%ld\n\n", info->installdate); + "%jd\n\n", (intmax_t)info->installdate); } if(info->packager) { fprintf(fp, "%%PACKAGER%%\n" @@ -813,41 +834,45 @@ int _alpm_local_db_write(alpm_db_t *db, alpm_pkg_t *info, alpm_dbinfrq_t inforeq fprintf(fp, "%%REASON%%\n" "%u\n\n", info->reason); } - if(info->depends) { - fputs("%DEPENDS%\n", fp); - for(lp = info->depends; lp; lp = lp->next) { - char *depstring = alpm_dep_compute_string(lp->data); - fprintf(fp, "%s\n", depstring); - free(depstring); + if(info->groups) { + fputs("%GROUPS%\n", fp); + for(lp = info->groups; lp; lp = lp->next) { + fputs(lp->data, fp); + fputc('\n', fp); + } + fputc('\n', fp); + } + if(info->licenses) { + fputs("%LICENSE%\n", fp); + for(lp = info->licenses; lp; lp = lp->next) { + fputs(lp->data, fp); + fputc('\n', fp); } - fprintf(fp, "\n"); + fputc('\n', fp); } - if(info->optdepends) { - fputs("%OPTDEPENDS%\n", fp); - for(lp = info->optdepends; lp; lp = lp->next) { - fprintf(fp, "%s\n", (char *)lp->data); + if(info->validation) { + fputs("%VALIDATION%\n", fp); + if(info->validation & ALPM_PKG_VALIDATION_NONE) { + fputs("none\n", fp); + } + if(info->validation & ALPM_PKG_VALIDATION_MD5SUM) { + fputs("md5\n", fp); } - fprintf(fp, "\n"); - } - if(info->conflicts) { - fputs("%CONFLICTS%\n", fp); - for(lp = info->conflicts; lp; lp = lp->next) { - char *depstring = alpm_dep_compute_string(lp->data); - fprintf(fp, "%s\n", depstring); - free(depstring); + if(info->validation & ALPM_PKG_VALIDATION_SHA256SUM) { + fputs("sha256\n", fp); } - fprintf(fp, "\n"); - } - if(info->provides) { - fputs("%PROVIDES%\n", fp); - for(lp = info->provides; lp; lp = lp->next) { - char *depstring = alpm_dep_compute_string(lp->data); - fprintf(fp, "%s\n", depstring); - free(depstring); + if(info->validation & ALPM_PKG_VALIDATION_SIGNATURE) { + fputs("pgp\n", fp); } - fprintf(fp, "\n"); + fputc('\n', fp); } + write_deps(fp, "%REPLACES%", info->replaces); + write_deps(fp, "%DEPENDS%", info->depends); + write_deps(fp, "%OPTDEPENDS%", info->optdepends); + write_deps(fp, "%CONFLICTS%", info->conflicts); + write_deps(fp, "%PROVIDES%", info->provides); + fclose(fp); fp = NULL; } @@ -855,7 +880,8 @@ int _alpm_local_db_write(alpm_db_t *db, alpm_pkg_t *info, alpm_dbinfrq_t inforeq /* FILES */ if(inforeq & INFRQ_FILES) { char *path; - _alpm_log(db->handle, ALPM_LOG_DEBUG, "writing %s-%s FILES information back to db\n", + _alpm_log(db->handle, ALPM_LOG_DEBUG, + "writing %s-%s FILES information back to db\n", info->name, info->version); path = _alpm_local_db_pkgpath(db, info, "files"); if(!path || (fp = fopen(path, "w")) == NULL) { @@ -868,20 +894,21 @@ int _alpm_local_db_write(alpm_db_t *db, alpm_pkg_t *info, alpm_dbinfrq_t inforeq free(path); if(info->files.count) { size_t i; - fprintf(fp, "%%FILES%%\n"); + fputs("%FILES%\n", fp); for(i = 0; i < info->files.count; i++) { const alpm_file_t *file = info->files.files + i; - fprintf(fp, "%s\n", file->name); + fputs(file->name, fp); + fputc('\n', fp); } - fprintf(fp, "\n"); + fputc('\n', fp); } if(info->backup) { - fprintf(fp, "%%BACKUP%%\n"); + fputs("%BACKUP%\n", fp); for(lp = info->backup; lp; lp = lp->next) { const alpm_backup_t *backup = lp->data; fprintf(fp, "%s\t%s\n", backup->name, backup->hash); } - fprintf(fp, "\n"); + fputc('\n', fp); } fclose(fp); fp = NULL; @@ -903,17 +930,71 @@ cleanup: int _alpm_local_db_remove(alpm_db_t *db, alpm_pkg_t *info) { int ret = 0; - char *pkgpath = _alpm_local_db_pkgpath(db, info, NULL); + DIR *dirp; + struct dirent *dp; + char *pkgpath; + size_t pkgpath_len; - /* TODO explicit file removes and then an rmdir? */ - ret = _alpm_rmrf(pkgpath); - free(pkgpath); - if(ret != 0) { + pkgpath = _alpm_local_db_pkgpath(db, info, NULL); + if(!pkgpath) { + return -1; + } + pkgpath_len = strlen(pkgpath); + + dirp = opendir(pkgpath); + if(!dirp) { + return -1; + } + /* go through the local DB entry, removing the files within, which we know + * are not nested directories of any kind. */ + for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { + if(strcmp(dp->d_name, "..") != 0 && strcmp(dp->d_name, ".") != 0) { + char name[PATH_MAX]; + if(pkgpath_len + strlen(dp->d_name) + 2 > PATH_MAX) { + /* file path is too long to remove, hmm. */ + ret = -1; + } else { + sprintf(name, "%s/%s", pkgpath, dp->d_name); + if(unlink(name)) { + ret = -1; + } + } + } + } + closedir(dirp); + + /* after removing all enclosed files, we can remove the directory itself. */ + if(rmdir(pkgpath)) { ret = -1; } + free(pkgpath); return ret; } +int SYMEXPORT alpm_pkg_set_reason(alpm_pkg_t *pkg, alpm_pkgreason_t reason) +{ + ASSERT(pkg != NULL, return -1); + ASSERT(pkg->origin == ALPM_PKG_FROM_LOCALDB, + RET_ERR(pkg->handle, ALPM_ERR_WRONG_ARGS, -1)); + ASSERT(pkg->origin_data.db == pkg->handle->db_local, + RET_ERR(pkg->handle, ALPM_ERR_WRONG_ARGS, -1)); + + _alpm_log(pkg->handle, ALPM_LOG_DEBUG, + "setting install reason %u for %s\n", reason, pkg->name); + if(alpm_pkg_get_reason(pkg) == reason) { + /* we are done */ + return 0; + } + /* set reason (in pkgcache) */ + pkg->reason = reason; + /* write DESC */ + if(_alpm_local_db_write(pkg->handle->db_local, pkg, INFRQ_DESC)) { + RET_ERR(pkg->handle, ALPM_ERR_DB_WRITE, -1); + } + + return 0; +} + struct db_operations local_db_ops = { .validate = local_db_validate, .populate = local_db_populate, diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c index 93b762a1..8c5b2d16 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -1,7 +1,7 @@ /* * be_package.c : backend for packages * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,11 +18,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <string.h> #include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> /* libarchive */ #include <archive.h> @@ -35,7 +36,13 @@ #include "log.h" #include "handle.h" #include "package.h" -#include "deps.h" /* _alpm_splitdep */ +#include "deps.h" +#include "filelist.h" + +struct package_changelog { + struct archive *archive; + int fd; +}; /** * Open a package changelog for reading. Similar to fopen in functionality, @@ -47,31 +54,38 @@ static void *_package_changelog_open(alpm_pkg_t *pkg) { ASSERT(pkg != NULL, return NULL); - struct archive *archive = NULL; + struct package_changelog *changelog; + struct archive *archive; struct archive_entry *entry; const char *pkgfile = pkg->origin_data.file; + struct stat buf; + int fd; - if((archive = archive_read_new()) == NULL) { - RET_ERR(pkg->handle, ALPM_ERR_LIBARCHIVE, NULL); - } - - archive_read_support_compression_all(archive); - archive_read_support_format_all(archive); - - if(archive_read_open_filename(archive, pkgfile, - ALPM_BUFFER_SIZE) != ARCHIVE_OK) { - RET_ERR(pkg->handle, ALPM_ERR_PKG_OPEN, NULL); + fd = _alpm_open_archive(pkg->handle, pkgfile, &buf, + &archive, ALPM_ERR_PKG_OPEN); + if(fd < 0) { + return NULL; } while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) { const char *entry_name = archive_entry_pathname(entry); if(strcmp(entry_name, ".CHANGELOG") == 0) { - return archive; + changelog = malloc(sizeof(struct package_changelog)); + if(!changelog) { + pkg->handle->pm_errno = ALPM_ERR_MEMORY; + archive_read_finish(archive); + CLOSE(fd); + return NULL; + } + changelog->archive = archive; + changelog->fd = fd; + return changelog; } } /* we didn't find a changelog */ archive_read_finish(archive); + CLOSE(fd); errno = ENOENT; return NULL; @@ -89,7 +103,8 @@ static void *_package_changelog_open(alpm_pkg_t *pkg) static size_t _package_changelog_read(void *ptr, size_t size, const alpm_pkg_t UNUSED *pkg, void *fp) { - ssize_t sret = archive_read_data((struct archive *)fp, ptr, size); + struct package_changelog *changelog = fp; + ssize_t sret = archive_read_data(changelog->archive, ptr, size); /* Report error (negative values) */ if(sret < 0) { RET_ERR(pkg->handle, ALPM_ERR_LIBARCHIVE, 0); @@ -107,7 +122,12 @@ static size_t _package_changelog_read(void *ptr, size_t size, */ static int _package_changelog_close(const alpm_pkg_t UNUSED *pkg, void *fp) { - return archive_read_finish((struct archive *)fp); + int ret; + struct package_changelog *changelog = fp; + ret = archive_read_finish(changelog->archive); + CLOSE(changelog->fd); + free(changelog); + return ret; } /** Package file operations struct accessor. We implement this as a method @@ -149,21 +169,24 @@ static int parse_descfile(alpm_handle_t *handle, struct archive *a, alpm_pkg_t * /* loop until we reach EOF or other error */ while((ret = _alpm_archive_fgets(a, &buf)) == ARCHIVE_OK) { - size_t len = _alpm_strip_newline(buf.line); + size_t len = _alpm_strip_newline(buf.line, buf.real_line_size); linenum++; - if(len == 0 || buf.line[0] == '#') { + key = buf.line; + if(len == 0 || key[0] == '#') { continue; } - ptr = buf.line; - key = strsep(&ptr, "="); - if(key == NULL || ptr == NULL) { - _alpm_log(handle, ALPM_LOG_DEBUG, "%s: syntax error in description file line %d\n", - newpkg->name ? newpkg->name : "error", linenum); + /* line is always in this format: "key = value" + * we can be sure the " = " exists, so look for that */ + ptr = memchr(key, ' ', len); + if(!ptr || (size_t)(ptr - key + 2) > len || memcmp(ptr, " = ", 3) != 0) { + _alpm_log(handle, ALPM_LOG_DEBUG, + "%s: syntax error in description file line %d\n", + newpkg->name ? newpkg->name : "error", linenum); } else { - key = _alpm_strtrim(key); - while(*ptr == ' ') ptr++; - ptr = _alpm_strtrim(ptr); + /* NULL the end of the key portion, move ptr to start of value */ + *ptr = '\0'; + ptr += 3; if(strcmp(key, "pkgname") == 0) { STRDUP(newpkg->name, ptr, return -1); newpkg->name_hash = _alpm_hash_sdbm(newpkg->name); @@ -192,7 +215,8 @@ static int parse_descfile(alpm_handle_t *handle, struct archive *a, alpm_pkg_t * alpm_depend_t *dep = _alpm_splitdep(ptr); newpkg->depends = alpm_list_add(newpkg->depends, dep); } else if(strcmp(key, "optdepend") == 0) { - newpkg->optdepends = alpm_list_add(newpkg->optdepends, strdup(ptr)); + alpm_depend_t *optdep = _alpm_splitdep(ptr); + newpkg->optdepends = alpm_list_add(newpkg->optdepends, optdep); } else if(strcmp(key, "conflict") == 0) { alpm_depend_t *conflict = _alpm_splitdep(ptr); newpkg->conflicts = alpm_list_add(newpkg->conflicts, conflict); @@ -225,53 +249,6 @@ static int parse_descfile(alpm_handle_t *handle, struct archive *a, alpm_pkg_t * return 0; } -static void files_merge(alpm_file_t a[], alpm_file_t b[], alpm_file_t c[], - size_t m, size_t n) -{ - size_t i = 0, j = 0, k = 0; - while(i < m && j < n) { - if(strcmp(a[i].name, b[j].name) < 0) { - c[k++] = a[i++]; - } else { - c[k++] = b[j++]; - } - } - while(i < m) { - c[k++] = a[i++]; - } - while(j < n) { - c[k++] = b[j++]; - } -} - -static alpm_file_t *files_msort(alpm_file_t *files, size_t n) -{ - alpm_file_t *work; - size_t blocksize = 1; - - CALLOC(work, n, sizeof(alpm_file_t), return NULL); - - for(blocksize = 1; blocksize < n; blocksize *= 2) { - size_t i, max_extent = 0; - for(i = 0; i < n - blocksize; i += 2 * blocksize) { - /* this limits our actual merge to the length of the array, since we will - * not likely be a perfect power of two. */ - size_t right_blocksize = blocksize; - if(i + blocksize * 2 > n) { - right_blocksize = n - i - blocksize; - } - files_merge(files + i, files + i + blocksize, work + i, - blocksize, right_blocksize); - max_extent = i + blocksize + right_blocksize; - } - /* ensure we only copy what we actually touched on this merge pass, - * no more, no less */ - memcpy(files, work, max_extent * sizeof(alpm_file_t)); - } - free(work); - return files; -} - /** * Validate a package. * @param handle the context handle @@ -280,11 +257,12 @@ static alpm_file_t *files_msort(alpm_file_t *files, size_t n) * sha256sum, and/or base64 signature) * @param level the required level of signature verification * @param sigdata signature data from the package to pass back + * @param validation successful validations performed on the package file * @return 0 if package is fully valid, -1 and pm_errno otherwise */ int _alpm_pkg_validate_internal(alpm_handle_t *handle, const char *pkgfile, alpm_pkg_t *syncpkg, alpm_siglevel_t level, - alpm_siglist_t **sigdata) + alpm_siglist_t **sigdata, alpm_pkgvalidation_t *validation) { int has_sig; handle->pm_errno = 0; @@ -294,8 +272,15 @@ int _alpm_pkg_validate_internal(alpm_handle_t *handle, } /* attempt to access the package file, ensure it exists */ - if(access(pkgfile, R_OK) != 0) { - RET_ERR(handle, ALPM_ERR_PKG_NOT_FOUND, -1); + if(_alpm_access(handle, NULL, pkgfile, R_OK) != 0) { + if(errno == ENOENT) { + handle->pm_errno = ALPM_ERR_PKG_NOT_FOUND; + } else if(errno == EACCES) { + handle->pm_errno = ALPM_ERR_BADPERMS; + } else { + handle->pm_errno = ALPM_ERR_PKG_OPEN; + } + return -1; } /* can we get away with skipping checksums? */ @@ -316,17 +301,23 @@ int _alpm_pkg_validate_internal(alpm_handle_t *handle, if(syncpkg->md5sum && !syncpkg->sha256sum) { _alpm_log(handle, ALPM_LOG_DEBUG, "md5sum: %s\n", syncpkg->md5sum); _alpm_log(handle, ALPM_LOG_DEBUG, "checking md5sum for %s\n", pkgfile); - if(_alpm_test_checksum(pkgfile, syncpkg->md5sum, ALPM_CSUM_MD5) != 0) { + if(_alpm_test_checksum(pkgfile, syncpkg->md5sum, ALPM_PKG_VALIDATION_MD5SUM) != 0) { RET_ERR(handle, ALPM_ERR_PKG_INVALID_CHECKSUM, -1); } + if(validation) { + *validation |= ALPM_PKG_VALIDATION_MD5SUM; + } } if(syncpkg->sha256sum) { _alpm_log(handle, ALPM_LOG_DEBUG, "sha256sum: %s\n", syncpkg->sha256sum); _alpm_log(handle, ALPM_LOG_DEBUG, "checking sha256sum for %s\n", pkgfile); - if(_alpm_test_checksum(pkgfile, syncpkg->sha256sum, ALPM_CSUM_SHA256) != 0) { + if(_alpm_test_checksum(pkgfile, syncpkg->sha256sum, ALPM_PKG_VALIDATION_SHA256SUM) != 0) { RET_ERR(handle, ALPM_ERR_PKG_INVALID_CHECKSUM, -1); } + if(validation) { + *validation |= ALPM_PKG_VALIDATION_SHA256SUM; + } } } @@ -340,6 +331,13 @@ int _alpm_pkg_validate_internal(alpm_handle_t *handle, handle->pm_errno = ALPM_ERR_PKG_INVALID_SIG; return -1; } + if(validation && has_sig) { + *validation |= ALPM_PKG_VALIDATION_SIGNATURE; + } + } + + if (validation && !*validation) { + *validation = ALPM_PKG_VALIDATION_NONE; } return 0; @@ -355,10 +353,10 @@ int _alpm_pkg_validate_internal(alpm_handle_t *handle, alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, const char *pkgfile, int full) { - int ret, config = 0; + int ret, fd, config = 0; struct archive *archive; struct archive_entry *entry; - alpm_pkg_t *newpkg = NULL; + alpm_pkg_t *newpkg; struct stat st; size_t files_size = 0; @@ -366,33 +364,26 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL); } - /* attempt to stat the package file, ensure it exists */ - if(stat(pkgfile, &st) == 0) { - newpkg = _alpm_pkg_new(); - if(newpkg == NULL) { - RET_ERR(handle, ALPM_ERR_MEMORY, NULL); + fd = _alpm_open_archive(handle, pkgfile, &st, &archive, ALPM_ERR_PKG_OPEN); + if(fd < 0) { + if(errno == ENOENT) { + handle->pm_errno = ALPM_ERR_PKG_NOT_FOUND; + } else if(errno == EACCES) { + handle->pm_errno = ALPM_ERR_BADPERMS; + } else { + handle->pm_errno = ALPM_ERR_PKG_OPEN; } - newpkg->filename = strdup(pkgfile); - newpkg->size = st.st_size; - } else { - /* couldn't stat the pkgfile, return an error */ - RET_ERR(handle, ALPM_ERR_PKG_NOT_FOUND, NULL); - } - - /* try to create an archive object to read in the package */ - if((archive = archive_read_new()) == NULL) { - _alpm_pkg_free(newpkg); - RET_ERR(handle, ALPM_ERR_LIBARCHIVE, NULL); + return NULL; } - archive_read_support_compression_all(archive); - archive_read_support_format_all(archive); - - if(archive_read_open_filename(archive, pkgfile, - ALPM_BUFFER_SIZE) != ARCHIVE_OK) { - handle->pm_errno = ALPM_ERR_PKG_OPEN; + newpkg = _alpm_pkg_new(); + if(newpkg == NULL) { + handle->pm_errno = ALPM_ERR_MEMORY; goto error; } + STRDUP(newpkg->filename, pkgfile, + handle->pm_errno = ALPM_ERR_MEMORY; goto error); + newpkg->size = st.st_size; _alpm_log(handle, ALPM_LOG_DEBUG, "starting package load for %s\n", pkgfile); @@ -439,7 +430,7 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, newfiles = realloc(newpkg->files.files, sizeof(alpm_file_t) * files_size); if(!newfiles) { - ALLOC_FAIL(sizeof(alpm_file_t) * files_size); + _alpm_alloc_fail(sizeof(alpm_file_t) * files_size); goto error; } /* ensure all new memory is zeroed out, in both the initial @@ -481,13 +472,15 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, } archive_read_finish(archive); + CLOSE(fd); /* internal fields for package struct */ - newpkg->origin = PKG_FROM_FILE; + newpkg->origin = ALPM_PKG_FROM_FILE; newpkg->origin_data.file = strdup(pkgfile); newpkg->ops = get_file_pkg_ops(); newpkg->handle = handle; newpkg->infolevel = INFRQ_BASE | INFRQ_DESC | INFRQ_SCRIPTLET; + newpkg->validation = ALPM_PKG_VALIDATION_NONE; if(full) { if(newpkg->files.files) { @@ -497,8 +490,9 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, /* "checking for conflicts" requires a sorted list, ensure that here */ _alpm_log(handle, ALPM_LOG_DEBUG, "sorting package filelist for %s\n", pkgfile); - newpkg->files.files = files_msort(newpkg->files.files, - newpkg->files.count); + + qsort(newpkg->files.files, newpkg->files.count, + sizeof(alpm_file_t), _alpm_files_cmp); } newpkg->infolevel |= INFRQ_FILES; } @@ -510,6 +504,9 @@ pkg_invalid: error: _alpm_pkg_free(newpkg); archive_read_finish(archive); + if(fd >= 0) { + CLOSE(fd); + } return NULL; } @@ -517,10 +514,13 @@ error: int SYMEXPORT alpm_pkg_load(alpm_handle_t *handle, const char *filename, int full, alpm_siglevel_t level, alpm_pkg_t **pkg) { + alpm_pkgvalidation_t validation = 0; + CHECK_HANDLE(handle, return -1); ASSERT(pkg != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1)); - if(_alpm_pkg_validate_internal(handle, filename, NULL, level, NULL) == -1) { + if(_alpm_pkg_validate_internal(handle, filename, NULL, level, NULL, + &validation) == -1) { /* pm_errno is set by pkg_validate */ return -1; } @@ -529,6 +529,7 @@ int SYMEXPORT alpm_pkg_load(alpm_handle_t *handle, const char *filename, int ful /* pm_errno is set by pkg_load */ return -1; } + (*pkg)->validation = validation; return 0; } diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index 3c990246..6bac6fbf 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -1,7 +1,7 @@ /* * be_sync.c : backend for sync databases * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,10 +18,10 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <errno.h> +#include <sys/types.h> #include <sys/stat.h> +#include <fcntl.h> #include <unistd.h> /* libarchive */ @@ -86,7 +86,7 @@ static int sync_db_validate(alpm_db_t *db) } /* we can skip any validation if the database doesn't exist */ - if(access(dbpath, R_OK) != 0 && errno == ENOENT) { + if(_alpm_access(db->handle, NULL, dbpath, R_OK) != 0 && errno == ENOENT) { db->status &= ~DB_STATUS_EXISTS; db->status |= DB_STATUS_MISSING; _alpm_log(db->handle, ALPM_LOG_WARNING, @@ -142,7 +142,7 @@ valid: * * Example: * @code - * alpm_list_t *syncs = alpm_option_get_syncdbs(); + * alpm_list_t *syncs = alpm_get_syncdbs(); * for(i = syncs; i; i = alpm_list_next(i)) { * alpm_db_t *db = alpm_list_getdata(i); * result = alpm_db_update(0, db); @@ -212,6 +212,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) /* print server + filename into a buffer */ len = strlen(server) + strlen(db->treename) + 5; + /* TODO fix leak syncpath and umask unset */ MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); snprintf(payload.fileurl, len, "%s/%s.db", server, db->treename); payload.handle = handle; @@ -234,6 +235,7 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db) /* if we downloaded a DB, we want the .sig from the same server */ /* print server + filename into a buffer (leave space for .sig) */ len = strlen(server) + strlen(db->treename) + 9; + /* TODO fix leak syncpath and umask unset */ MALLOC(payload.fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); snprintf(payload.fileurl, len, "%s/%s.db.sig", server, db->treename); payload.handle = handle; @@ -294,6 +296,29 @@ cleanup: static int sync_db_read(alpm_db_t *db, struct archive *archive, struct archive_entry *entry, alpm_pkg_t **likely_pkg); +static alpm_pkgvalidation_t _sync_get_validation(alpm_pkg_t *pkg) +{ + if(pkg->validation) { + return pkg->validation; + } + + if(pkg->md5sum) { + pkg->validation |= ALPM_PKG_VALIDATION_MD5SUM; + } + if(pkg->sha256sum) { + pkg->validation |= ALPM_PKG_VALIDATION_SHA256SUM; + } + if(pkg->base64_sig) { + pkg->validation |= ALPM_PKG_VALIDATION_SIGNATURE; + } + + if(!pkg->validation) { + pkg->validation |= ALPM_PKG_VALIDATION_NONE; + } + + return pkg->validation; +} + static alpm_pkg_t *load_pkg_for_entry(alpm_db_t *db, const char *entryname, const char **entry_filename, alpm_pkg_t *likely_pkg) { @@ -316,7 +341,8 @@ static alpm_pkg_t *load_pkg_for_entry(alpm_db_t *db, const char *entryname, return NULL; } - if(likely_pkg && strcmp(likely_pkg->name, pkgname) == 0) { + if(likely_pkg && pkgname_hash == likely_pkg->name_hash + && strcmp(likely_pkg->name, pkgname) == 0) { pkg = likely_pkg; } else { pkg = _alpm_pkghash_find(db->pkgcache, pkgname); @@ -331,9 +357,10 @@ static alpm_pkg_t *load_pkg_for_entry(alpm_db_t *db, const char *entryname, pkg->version = pkgver; pkg->name_hash = pkgname_hash; - pkg->origin = PKG_FROM_SYNCDB; + pkg->origin = ALPM_PKG_FROM_SYNCDB; pkg->origin_data.db = db; pkg->ops = &default_pkg_ops; + pkg->ops->get_validation = _sync_get_validation; pkg->handle = db->handle; /* add to the collection */ @@ -348,61 +375,38 @@ static alpm_pkg_t *load_pkg_for_entry(alpm_db_t *db, const char *entryname, return pkg; } -/* - * This is the data table used to generate the estimating function below. - * "Weighted Avg" means averaging the bottom table values; thus each repo, big - * or small, will have equal influence. "Unweighted Avg" means averaging the - * sums of the top table columns, thus each package has equal influence. The - * final values are calculated by (surprise) averaging the averages, because - * why the hell not. - * - * Database Pkgs tar bz2 gz xz - * community 2096 5294080 256391 421227 301296 - * core 180 460800 25257 36850 29356 - * extra 2606 6635520 294647 470818 339392 - * multilib 126 327680 16120 23261 18732 - * testing 76 204800 10902 14348 12100 - * - * Bytes Per Package - * community 2096 2525.80 122.32 200.97 143.75 - * core 180 2560.00 140.32 204.72 163.09 - * extra 2606 2546.25 113.06 180.67 130.23 - * multilib 126 2600.63 127.94 184.61 148.67 - * testing 76 2694.74 143.45 188.79 159.21 - - * Weighted Avg 2585.48 129.42 191.95 148.99 - * Unweighted Avg 2543.39 118.74 190.16 137.93 - * Average of Avgs 2564.44 124.08 191.06 143.46 - */ +/* This function doesn't work as well as one might think, as size of database + * entries varies considerably. Adding signatures nearly doubles the size of a + * single entry; deltas also can make for large variations in size. These + * current values are heavily influenced by Arch Linux; databases with no + * deltas and a single signature per package. */ static size_t estimate_package_count(struct stat *st, struct archive *archive) { - unsigned int per_package; + int per_package; switch(archive_compression(archive)) { case ARCHIVE_COMPRESSION_NONE: - per_package = 2564; + per_package = 3015; break; case ARCHIVE_COMPRESSION_GZIP: - per_package = 191; + case ARCHIVE_COMPRESSION_COMPRESS: + per_package = 464; break; case ARCHIVE_COMPRESSION_BZIP2: - per_package = 124; - break; - case ARCHIVE_COMPRESSION_COMPRESS: - per_package = 193; + per_package = 394; break; case ARCHIVE_COMPRESSION_LZMA: case ARCHIVE_COMPRESSION_XZ: - per_package = 143; + per_package = 400; break; #ifdef ARCHIVE_COMPRESSION_UU case ARCHIVE_COMPRESSION_UU: - per_package = 3543; + per_package = 3015 * 4 / 3; break; #endif default: /* assume it is at least somewhat compressed */ - per_package = 200; + per_package = 500; } return (size_t)((st->st_size / per_package) + 1); } @@ -411,7 +415,7 @@ static int sync_db_populate(alpm_db_t *db) { const char *dbpath; size_t est_count; - int count = 0; + int count, fd; struct stat buf; struct archive *archive; struct archive_entry *entry; @@ -423,38 +427,24 @@ static int sync_db_populate(alpm_db_t *db) if(db->status & DB_STATUS_MISSING) { RET_ERR(db->handle, ALPM_ERR_DB_NOT_FOUND, -1); } - - if((archive = archive_read_new()) == NULL) { - RET_ERR(db->handle, ALPM_ERR_LIBARCHIVE, -1); - } - - archive_read_support_compression_all(archive); - archive_read_support_format_all(archive); - dbpath = _alpm_db_path(db); if(!dbpath) { /* pm_errno set in _alpm_db_path() */ return -1; } - _alpm_log(db->handle, ALPM_LOG_DEBUG, "opening database archive %s\n", dbpath); - - if(archive_read_open_filename(archive, dbpath, - ALPM_BUFFER_SIZE) != ARCHIVE_OK) { - _alpm_log(db->handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), dbpath, - archive_error_string(archive)); - archive_read_finish(archive); - RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1); - } - if(stat(dbpath, &buf) != 0) { - RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1); + fd = _alpm_open_archive(db->handle, dbpath, &buf, + &archive, ALPM_ERR_DB_OPEN); + if(fd < 0) { + return -1; } est_count = estimate_package_count(&buf, archive); - /* initialize hash at 66% full */ - db->pkgcache = _alpm_pkghash_create(est_count * 3 / 2); + db->pkgcache = _alpm_pkghash_create(est_count); if(db->pkgcache == NULL) { - RET_ERR(db->handle, ALPM_ERR_MEMORY, -1); + db->handle->pm_errno = ALPM_ERR_MEMORY; + count = -1; + goto cleanup; } while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) { @@ -473,21 +463,26 @@ static int sync_db_populate(alpm_db_t *db) } count = alpm_list_count(db->pkgcache->list); - if(count > 0) { - db->pkgcache->list = alpm_list_msort(db->pkgcache->list, (size_t)count, _alpm_pkg_cmp); + db->pkgcache->list = alpm_list_msort(db->pkgcache->list, + (size_t)count, _alpm_pkg_cmp); } - archive_read_finish(archive); - _alpm_log(db->handle, ALPM_LOG_DEBUG, "added %d packages to package cache for db '%s'\n", + _alpm_log(db->handle, ALPM_LOG_DEBUG, + "added %d packages to package cache for db '%s'\n", count, db->treename); +cleanup: + archive_read_finish(archive); + if(fd >= 0) { + CLOSE(fd); + } return count; } #define READ_NEXT() do { \ if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \ line = buf.line; \ - _alpm_strip_newline(line); \ + _alpm_strip_newline(line, buf.real_line_size); \ } while(0) #define READ_AND_STORE(f) do { \ @@ -498,14 +493,14 @@ static int sync_db_populate(alpm_db_t *db) #define READ_AND_STORE_ALL(f) do { \ char *linedup; \ if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \ - if(_alpm_strip_newline(buf.line) == 0) break; \ + if(_alpm_strip_newline(buf.line, buf.real_line_size) == 0) break; \ STRDUP(linedup, buf.line, goto error); \ f = alpm_list_add(f, linedup); \ } while(1) /* note the while(1) and not (0) */ #define READ_AND_SPLITDEP(f) do { \ if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \ - if(_alpm_strip_newline(buf.line) == 0) break; \ + if(_alpm_strip_newline(buf.line, buf.real_line_size) == 0) break; \ f = alpm_list_add(f, _alpm_splitdep(line)); \ } while(1) /* note the while(1) and not (0) */ @@ -544,7 +539,7 @@ static int sync_db_read(alpm_db_t *db, struct archive *archive, int ret; while((ret = _alpm_archive_fgets(archive, &buf)) == ARCHIVE_OK) { char *line = buf.line; - if(_alpm_strip_newline(line) == 0) { + if(_alpm_strip_newline(line, buf.real_line_size) == 0) { /* length of stripped line was zero */ continue; } @@ -595,7 +590,19 @@ static int sync_db_read(alpm_db_t *db, struct archive *archive, } else if(strcmp(line, "%DEPENDS%") == 0) { READ_AND_SPLITDEP(pkg->depends); } else if(strcmp(line, "%OPTDEPENDS%") == 0) { - READ_AND_STORE_ALL(pkg->optdepends); + READ_AND_SPLITDEP(pkg->optdepends); + } else if(strcmp(line, "%MAKEDEPENDS%") == 0) { + /* currently unused */ + while(1) { + READ_NEXT(); + if(strlen(line) == 0) break; + } + } else if(strcmp(line, "%CHECKDEPENDS%") == 0) { + /* currently unused */ + while(1) { + READ_NEXT(); + if(strlen(line) == 0) break; + } } else if(strcmp(line, "%CONFLICTS%") == 0) { READ_AND_SPLITDEP(pkg->conflicts); } else if(strcmp(line, "%PROVIDES%") == 0) { @@ -605,7 +612,8 @@ static int sync_db_read(alpm_db_t *db, struct archive *archive, while(1) { READ_NEXT(); if(strlen(line) == 0) break; - pkg->deltas = alpm_list_add(pkg->deltas, _alpm_delta_parse(line)); + pkg->deltas = alpm_list_add(pkg->deltas, + _alpm_delta_parse(db->handle, line)); } } } diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c index 6bfd256f..ccfe990c 100644 --- a/lib/libalpm/conflict.c +++ b/lib/libalpm/conflict.c @@ -1,7 +1,7 @@ /* * conflict.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2006 by David Kimpe <dnaku@frugalware.org> @@ -22,8 +22,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -40,6 +38,7 @@ #include "util.h" #include "log.h" #include "deps.h" +#include "filelist.h" static alpm_conflict_t *conflict_new(alpm_pkg_t *pkg1, alpm_pkg_t *pkg2, alpm_depend_t *reason) @@ -215,67 +214,6 @@ alpm_list_t SYMEXPORT *alpm_checkconflicts(alpm_handle_t *handle, return _alpm_innerconflicts(handle, pkglist); } -static const int DIFFERENCE = 0; -static const int INTERSECT = 1; -/* Returns a set operation on the provided two lists of files. - * Pre-condition: both lists are sorted! - * When done, free the list but NOT the contained data. - * - * Operations: - * DIFFERENCE - a difference operation is performed. filesA - filesB. - * INTERSECT - an intersection operation is performed. filesA & filesB. - */ -static alpm_list_t *filelist_operation(alpm_filelist_t *filesA, - alpm_filelist_t *filesB, int operation) -{ - alpm_list_t *ret = NULL; - size_t ctrA = 0, ctrB = 0; - - while(ctrA < filesA->count && ctrB < filesB->count) { - alpm_file_t *fileA = filesA->files + ctrA; - alpm_file_t *fileB = filesB->files + ctrB; - const char *strA = fileA->name; - const char *strB = fileB->name; - /* skip directories, we don't care about them */ - if(strA[strlen(strA)-1] == '/') { - ctrA++; - } else if(strB[strlen(strB)-1] == '/') { - ctrB++; - } else { - int cmp = strcmp(strA, strB); - if(cmp < 0) { - if(operation == DIFFERENCE) { - /* item only in filesA, qualifies as a difference */ - ret = alpm_list_add(ret, fileA); - } - ctrA++; - } else if(cmp > 0) { - ctrB++; - } else { - if(operation == INTERSECT) { - /* item in both, qualifies as an intersect */ - ret = alpm_list_add(ret, fileA); - } - ctrA++; - ctrB++; - } - } - } - - /* if doing a difference, ensure we have completely emptied pA */ - while(operation == DIFFERENCE && ctrA < filesA->count) { - alpm_file_t *fileA = filesA->files + ctrA; - const char *strA = fileA->name; - /* skip directories */ - if(strA[strlen(strA)-1] != '/') { - ret = alpm_list_add(ret, fileA); - } - ctrA++; - } - - return ret; -} - /* Adds alpm_fileconflict_t to a conflicts list. Pass the conflicts list, the * conflicting file path, and either two packages or one package and NULL. */ @@ -314,20 +252,6 @@ void _alpm_fileconflict_free(alpm_fileconflict_t *conflict) FREE(conflict); } -const alpm_file_t *_alpm_filelist_contains(alpm_filelist_t *filelist, - const char *name) -{ - size_t i; - const alpm_file_t *file = filelist->files; - for(i = 0; i < filelist->count; i++) { - if(strcmp(file->name, name) == 0) { - return file; - } - file++; - } - return NULL; -} - static int dir_belongsto_pkg(alpm_handle_t *handle, const char *dirpath, alpm_pkg_t *pkg) { @@ -340,7 +264,7 @@ static int dir_belongsto_pkg(alpm_handle_t *handle, const char *dirpath, const char *root = handle->root; /* check directory is actually in package - used for subdirectory checks */ - if(!_alpm_filelist_contains(alpm_pkg_get_files(pkg), dirpath)) { + if(!alpm_filelist_contains(alpm_pkg_get_files(pkg), dirpath)) { _alpm_log(handle, ALPM_LOG_DEBUG, "directory %s not in package %s\n", dirpath, pkg->name); return 0; @@ -358,7 +282,7 @@ static int dir_belongsto_pkg(alpm_handle_t *handle, const char *dirpath, continue; } - if(_alpm_filelist_contains(alpm_pkg_get_files(i->data), dirpath)) { + if(alpm_filelist_contains(alpm_pkg_get_files(i->data), dirpath)) { _alpm_log(handle, ALPM_LOG_DEBUG, "file %s also in package %s\n", dirpath, ((alpm_pkg_t*)i->data)->name); @@ -392,7 +316,7 @@ static int dir_belongsto_pkg(alpm_handle_t *handle, const char *dirpath, return 0; } } else { - if(_alpm_filelist_contains(alpm_pkg_get_files(pkg), path)) { + if(alpm_filelist_contains(alpm_pkg_get_files(pkg), path)) { continue; } else { closedir(dir); @@ -410,16 +334,19 @@ static int dir_belongsto_pkg(alpm_handle_t *handle, const char *dirpath, * 1: check every target against every target * 2: check every target against the filesystem */ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, - alpm_list_t *upgrade, alpm_list_t *remove) + alpm_list_t *upgrade, alpm_list_t *rem) { alpm_list_t *i, *conflicts = NULL; size_t numtargs = alpm_list_count(upgrade); size_t current; + size_t rootlen; if(!upgrade) { return NULL; } + rootlen = strlen(handle->root); + /* TODO this whole function needs a huge change, which hopefully will * be possible with real transactions. Right now we only do half as much * here as we do when we actually extract files in add.c with our 12 @@ -440,8 +367,8 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, for(j = i->next; j; j = j->next) { alpm_list_t *common_files; alpm_pkg_t *p2 = j->data; - common_files = filelist_operation(alpm_pkg_get_files(p1), - alpm_pkg_get_files(p2), INTERSECT); + common_files = _alpm_filelist_intersection(alpm_pkg_get_files(p1), + alpm_pkg_get_files(p2)); if(common_files) { alpm_list_t *k; @@ -473,8 +400,8 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, if(dbpkg) { alpm_list_t *difference; /* older ver of package currently installed */ - difference = filelist_operation(alpm_pkg_get_files(p1), - alpm_pkg_get_files(dbpkg), DIFFERENCE); + difference = _alpm_filelist_difference(alpm_pkg_get_files(p1), + alpm_pkg_get_files(dbpkg)); tmpfiles.count = alpm_list_count(difference); tmpfiles.files = alpm_list_to_array(difference, tmpfiles.count, sizeof(alpm_file_t)); @@ -493,8 +420,9 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, int resolved_conflict = 0; struct stat lsbuf; char path[PATH_MAX]; + size_t pathlen; - snprintf(path, PATH_MAX, "%s%s", handle->root, filestr); + pathlen = snprintf(path, PATH_MAX, "%s%s", handle->root, filestr); /* stat the file - if it exists, do some checks */ if(_alpm_lstat(path, &lsbuf) != 0) { @@ -518,15 +446,15 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, /* if we made it to here, we want all subsequent path comparisons to * not include the trailing slash. This allows things like file -> * directory replacements. */ - path[strlen(path) - 1] = '\0'; + path[pathlen - 1] = '\0'; } - relative_path = path + strlen(handle->root); + relative_path = path + rootlen; /* Check remove list (will we remove the conflicting local file?) */ - for(k = remove; k && !resolved_conflict; k = k->next) { + for(k = rem; k && !resolved_conflict; k = k->next) { alpm_pkg_t *rempkg = k->data; - if(rempkg && _alpm_filelist_contains(alpm_pkg_get_files(rempkg), + if(rempkg && alpm_filelist_contains(alpm_pkg_get_files(rempkg), relative_path)) { _alpm_log(handle, ALPM_LOG_DEBUG, "local file will be removed, not a conflict\n"); @@ -543,7 +471,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, alpm_pkg_t *localp2 = _alpm_db_get_pkgfromcache(handle->db_local, p2->name); /* localp2->files will be removed (target conflicts are handled by CHECK 1) */ - if(localp2 && _alpm_filelist_contains(alpm_pkg_get_files(localp2), filestr)) { + if(localp2 && alpm_filelist_contains(alpm_pkg_get_files(localp2), filestr)) { /* skip removal of file, but not add. this will prevent a second * package from removing the file when it was already installed * by its new owner (whether the file is in backup array or not */ @@ -559,7 +487,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, if(!resolved_conflict && S_ISDIR(lsbuf.st_mode) && dbpkg) { char *dir = malloc(strlen(filestr) + 2); sprintf(dir, "%s/", filestr); - if(_alpm_filelist_contains(alpm_pkg_get_files(dbpkg), dir)) { + if(alpm_filelist_contains(alpm_pkg_get_files(dbpkg), dir)) { _alpm_log(handle, ALPM_LOG_DEBUG, "checking if all files in %s belong to %s\n", dir, dbpkg->name); @@ -573,17 +501,15 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, * consideration cannot itself be a link, as it might be unowned- path * components can be safely checked as all directories are "unowned". */ if(!resolved_conflict && dbpkg && !S_ISLNK(lsbuf.st_mode)) { - char *rpath = calloc(PATH_MAX, sizeof(char)); - const char *relative_rpath; + char rpath[PATH_MAX]; if(realpath(path, rpath)) { - relative_rpath = rpath + strlen(handle->root); - if(_alpm_filelist_contains(alpm_pkg_get_files(dbpkg), relative_rpath)) { + const char *relative_rpath = rpath + rootlen; + if(alpm_filelist_contains(alpm_pkg_get_files(dbpkg), relative_rpath)) { _alpm_log(handle, ALPM_LOG_DEBUG, "package contained the resolved realpath\n"); resolved_conflict = 1; } } - free(rpath); } /* is the file unowned and in the backup list of the new package? */ @@ -591,7 +517,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, alpm_list_t *local_pkgs = _alpm_db_get_pkgcache(handle->db_local); int found = 0; for(k = local_pkgs; k && !found; k = k->next) { - if(_alpm_filelist_contains(alpm_pkg_get_files(k->data), filestr)) { + if(alpm_filelist_contains(alpm_pkg_get_files(k->data), filestr)) { found = 1; } } @@ -607,7 +533,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, if(handle->pm_errno == ALPM_ERR_MEMORY) { FREELIST(conflicts); if(dbpkg) { - /* only freed if it was generated from filelist_operation() */ + /* only freed if it was generated from _alpm_filelist_difference() */ free(tmpfiles.files); } return NULL; @@ -615,7 +541,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, } } if(dbpkg) { - /* only freed if it was generated from filelist_operation() */ + /* only freed if it was generated from _alpm_filelist_difference() */ free(tmpfiles.files); } } diff --git a/lib/libalpm/conflict.h b/lib/libalpm/conflict.h index 8b7471fd..0bfdfd76 100644 --- a/lib/libalpm/conflict.h +++ b/lib/libalpm/conflict.h @@ -1,7 +1,7 @@ /* * conflict.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -33,9 +33,6 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, void _alpm_fileconflict_free(alpm_fileconflict_t *conflict); -const alpm_file_t *_alpm_filelist_contains(alpm_filelist_t *filelist, - const char *name); - #endif /* _ALPM_CONFLICT_H */ /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c index 8688a3cd..953f2af6 100644 --- a/lib/libalpm/db.c +++ b/lib/libalpm/db.c @@ -1,7 +1,7 @@ /* * db.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -22,8 +22,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -45,7 +43,7 @@ */ /** Register a sync database of packages. */ -alpm_db_t SYMEXPORT *alpm_db_register_sync(alpm_handle_t *handle, +alpm_db_t SYMEXPORT *alpm_register_syncdb(alpm_handle_t *handle, const char *treename, alpm_siglevel_t level) { /* Sanity checks */ @@ -70,7 +68,7 @@ void _alpm_db_unregister(alpm_db_t *db) } /** Unregister all package databases. */ -int SYMEXPORT alpm_db_unregister_all(alpm_handle_t *handle) +int SYMEXPORT alpm_unregister_all_syncdbs(alpm_handle_t *handle) { alpm_list_t *i; alpm_db_t *db; @@ -109,7 +107,7 @@ int SYMEXPORT alpm_db_unregister(alpm_db_t *db) } else { /* Warning : this function shouldn't be used to unregister all sync * databases by walking through the list returned by - * alpm_option_get_syncdbs, because the db is removed from that list here. + * alpm_get_syncdbs, because the db is removed from that list here. */ void *data; handle->dbs_sync = alpm_list_remove(handle->dbs_sync, @@ -263,7 +261,7 @@ alpm_list_t SYMEXPORT *alpm_db_get_pkgcache(alpm_db_t *db) } /** Get a group entry from a package database. */ -alpm_group_t SYMEXPORT *alpm_db_readgroup(alpm_db_t *db, const char *name) +alpm_group_t SYMEXPORT *alpm_db_get_group(alpm_db_t *db, const char *name) { ASSERT(db != NULL, return NULL); db->handle->pm_errno = 0; @@ -283,7 +281,7 @@ alpm_list_t SYMEXPORT *alpm_db_get_groupcache(alpm_db_t *db) } /** Searches a database. */ -alpm_list_t SYMEXPORT *alpm_db_search(alpm_db_t *db, const alpm_list_t* needles) +alpm_list_t SYMEXPORT *alpm_db_search(alpm_db_t *db, const alpm_list_t *needles) { ASSERT(db != NULL, return NULL); db->handle->pm_errno = 0; @@ -291,32 +289,6 @@ alpm_list_t SYMEXPORT *alpm_db_search(alpm_db_t *db, const alpm_list_t* needles) return _alpm_db_search(db, needles); } -/** Set install reason for a package in db. */ -int SYMEXPORT alpm_db_set_pkgreason(alpm_handle_t *handle, alpm_pkg_t *pkg, - alpm_pkgreason_t reason) -{ - CHECK_HANDLE(handle, return -1); - ASSERT(pkg != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1)); - ASSERT(pkg->origin == PKG_FROM_LOCALDB, - RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1)); - ASSERT(pkg->origin_data.db == handle->db_local, - RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1)); - - _alpm_log(handle, ALPM_LOG_DEBUG, - "setting install reason %u for %s\n", reason, pkg->name); - if(alpm_pkg_get_reason(pkg) == reason) { - /* we are done */ - return 0; - } - /* set reason (in pkgcache) */ - pkg->reason = reason; - /* write DESC */ - if(_alpm_local_db_write(handle->db_local, pkg, INFRQ_DESC)) { - RET_ERR(handle, ALPM_ERR_DB_WRITE, -1); - } - - return 0; -} /** @} */ diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h index 224bfbeb..94659b77 100644 --- a/lib/libalpm/db.h +++ b/lib/libalpm/db.h @@ -1,7 +1,7 @@ /* * db.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org> @@ -22,8 +22,6 @@ #ifndef _ALPM_DB_H #define _ALPM_DB_H -#include <time.h> - /* libarchive */ #include <archive.h> #include <archive_entry.h> diff --git a/lib/libalpm/delta.c b/lib/libalpm/delta.c index 6315a851..26ae5d5d 100644 --- a/lib/libalpm/delta.c +++ b/lib/libalpm/delta.c @@ -1,7 +1,7 @@ /* * delta.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2007-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <string.h> #include <stdint.h> /* intmax_t */ @@ -266,7 +264,8 @@ static alpm_list_t *find_unused(alpm_list_t *deltas, const char *to, off_t quota alpm_list_t SYMEXPORT *alpm_pkg_unused_deltas(alpm_pkg_t *pkg) { ASSERT(pkg != NULL, return NULL); - return find_unused(pkg->deltas, pkg->filename, pkg->size * MAX_DELTA_RATIO); + return find_unused(pkg->deltas, pkg->filename, + pkg->size * pkg->handle->deltaratio); } /** @} */ @@ -275,51 +274,54 @@ alpm_list_t SYMEXPORT *alpm_pkg_unused_deltas(alpm_pkg_t *pkg) * This function assumes that the string is in the correct format. * This format is as follows: * $deltafile $deltamd5 $deltasize $oldfile $newfile + * @param handle the context handle * @param line the string to parse * @return A pointer to the new alpm_delta_t object */ -/* TODO this does not really belong here, but in a parsing lib */ -alpm_delta_t *_alpm_delta_parse(char *line) +alpm_delta_t *_alpm_delta_parse(alpm_handle_t *handle, const char *line) { alpm_delta_t *delta; - char *tmp = line, *tmp2; - regex_t reg; - - regcomp(®, - "^[^[:space:]]* [[:xdigit:]]{32} [[:digit:]]*" - " [^[:space:]]* [^[:space:]]*$", - REG_EXTENDED | REG_NOSUB | REG_NEWLINE); - if(regexec(®, line, 0, 0, 0) != 0) { + const int num_matches = 6; + size_t len; + regmatch_t pmatch[num_matches]; + char filesize[32]; + + /* this is so we only have to compile the pattern once */ + if(!handle->delta_regex_compiled) { + /* $deltafile $deltamd5 $deltasize $oldfile $newfile*/ + regcomp(&handle->delta_regex, + "^([^[:space:]]+) ([[:xdigit:]]{32}) ([[:digit:]]+)" + " ([^[:space:]]+) ([^[:space:]]+)$", + REG_EXTENDED | REG_NEWLINE); + handle->delta_regex_compiled = 1; + } + + if(regexec(&handle->delta_regex, line, num_matches, pmatch, 0) != 0) { /* delta line is invalid, return NULL */ - regfree(®); return NULL; } - regfree(®); CALLOC(delta, 1, sizeof(alpm_delta_t), return NULL); - tmp2 = tmp; - tmp = strchr(tmp, ' '); - *(tmp++) = '\0'; - STRDUP(delta->delta, tmp2, return NULL); + /* start at index 1 -- match 0 is the entire match */ + len = pmatch[1].rm_eo - pmatch[1].rm_so; + STRNDUP(delta->delta, &line[pmatch[1].rm_so], len, return NULL); - tmp2 = tmp; - tmp = strchr(tmp, ' '); - *(tmp++) = '\0'; - STRDUP(delta->delta_md5, tmp2, return NULL); + len = pmatch[2].rm_eo - pmatch[2].rm_so; + STRNDUP(delta->delta_md5, &line[pmatch[2].rm_so], len, return NULL); - tmp2 = tmp; - tmp = strchr(tmp, ' '); - *(tmp++) = '\0'; - delta->delta_size = _alpm_strtoofft(tmp2); + len = pmatch[3].rm_eo - pmatch[3].rm_so; + if(len < sizeof(filesize)) { + strncpy(filesize, &line[pmatch[3].rm_so], len); + filesize[len] = '\0'; + delta->delta_size = _alpm_strtoofft(filesize); + } - tmp2 = tmp; - tmp = strchr(tmp, ' '); - *(tmp++) = '\0'; - STRDUP(delta->from, tmp2, return NULL); + len = pmatch[4].rm_eo - pmatch[4].rm_so; + STRNDUP(delta->from, &line[pmatch[4].rm_so], len, return NULL); - tmp2 = tmp; - STRDUP(delta->to, tmp2, return NULL); + len = pmatch[5].rm_eo - pmatch[5].rm_so; + STRNDUP(delta->to, &line[pmatch[5].rm_so], len, return NULL); return delta; } diff --git a/lib/libalpm/delta.h b/lib/libalpm/delta.h index 05df4207..b1c89912 100644 --- a/lib/libalpm/delta.h +++ b/lib/libalpm/delta.h @@ -1,7 +1,7 @@ /* * delta.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2007-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -20,21 +20,16 @@ #ifndef _ALPM_DELTA_H #define _ALPM_DELTA_H -#include "config.h" /* ensure off_t is correct length */ - #include <sys/types.h> /* off_t */ #include "alpm.h" -alpm_delta_t *_alpm_delta_parse(char *line); +alpm_delta_t *_alpm_delta_parse(alpm_handle_t *handle, const char *line); void _alpm_delta_free(alpm_delta_t *delta); alpm_delta_t *_alpm_delta_dup(const alpm_delta_t *delta); off_t _alpm_shortest_delta_path(alpm_handle_t *handle, alpm_list_t *deltas, const char *to, alpm_list_t **path); -/* max percent of package size to download deltas */ -#define MAX_DELTA_RATIO 0.7 - #endif /* _ALPM_DELTA_H */ /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/deps.c b/lib/libalpm/deps.c index 0c0a054e..2a06bb04 100644 --- a/lib/libalpm/deps.c +++ b/lib/libalpm/deps.c @@ -1,7 +1,7 @@ /* * deps.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org> @@ -20,8 +20,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -41,6 +39,7 @@ void _alpm_dep_free(alpm_depend_t *dep) { FREE(dep->name); FREE(dep->version); + FREE(dep->desc); FREE(dep); } @@ -159,15 +158,17 @@ alpm_list_t *_alpm_sortbydeps(alpm_handle_t *handle, else if(nextchild->state == -1) { alpm_pkg_t *vertexpkg = vertex->data; alpm_pkg_t *childpkg = nextchild->data; - const char *message; _alpm_log(handle, ALPM_LOG_WARNING, _("dependency cycle detected:\n")); if(reverse) { - message =_("%s will be removed after its %s dependency\n"); + _alpm_log(handle, ALPM_LOG_WARNING, + _("%s will be removed after its %s dependency\n"), + vertexpkg->name, childpkg->name); } else { - message =_("%s will be installed before its %s dependency\n"); + _alpm_log(handle, ALPM_LOG_WARNING, + _("%s will be installed before its %s dependency\n"), + vertexpkg->name, childpkg->name); } - _alpm_log(handle, ALPM_LOG_WARNING, message, vertexpkg->name, childpkg->name); } } if(!found) { @@ -204,8 +205,10 @@ alpm_list_t *_alpm_sortbydeps(alpm_handle_t *handle, static int no_dep_version(alpm_handle_t *handle) { - int flags = alpm_trans_get_flags(handle); - return flags != -1 && (flags & ALPM_TRANS_FLAG_NODEPVERSION); + if(!handle->trans) { + return 0; + } + return (handle->trans->flags & ALPM_TRANS_FLAG_NODEPVERSION); } static alpm_depend_t *filtered_depend(alpm_depend_t *dep, int nodepversion) @@ -266,7 +269,7 @@ alpm_pkg_t SYMEXPORT *alpm_find_satisfier(alpm_list_t *pkgs, const char *depstri * @return an alpm_list_t* of alpm_depmissing_t pointers. */ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle, - alpm_list_t *pkglist, alpm_list_t *remove, alpm_list_t *upgrade, + alpm_list_t *pkglist, alpm_list_t *rem, alpm_list_t *upgrade, int reversedeps) { alpm_list_t *i, *j; @@ -278,7 +281,7 @@ alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle, for(i = pkglist; i; i = i->next) { alpm_pkg_t *pkg = i->data; - if(_alpm_pkg_find(remove, pkg->name) || _alpm_pkg_find(upgrade, pkg->name)) { + if(_alpm_pkg_find(rem, pkg->name) || _alpm_pkg_find(upgrade, pkg->name)) { modified = alpm_list_add(modified, pkg); } else { dblist = alpm_list_add(dblist, pkg); @@ -395,7 +398,7 @@ int _alpm_depcmp(alpm_pkg_t *pkg, alpm_depend_t *dep) /* any version will satisfy the requirement */ satisfy = (provision->name_hash == dep->name_hash && strcmp(provision->name, dep->name) == 0); - } else if (provision->mod == ALPM_DEP_MOD_EQ) { + } else if(provision->mod == ALPM_DEP_MOD_EQ) { /* provision specifies a version, so try it out */ satisfy = (provision->name_hash == dep->name_hash && strcmp(provision->name, dep->name) == 0 @@ -409,7 +412,7 @@ int _alpm_depcmp(alpm_pkg_t *pkg, alpm_depend_t *dep) alpm_depend_t *_alpm_splitdep(const char *depstring) { alpm_depend_t *depend; - const char *ptr, *version; + const char *ptr, *version, *desc; size_t deplen; if(depstring == NULL) { @@ -417,7 +420,17 @@ alpm_depend_t *_alpm_splitdep(const char *depstring) } MALLOC(depend, sizeof(alpm_depend_t), return NULL); - deplen = strlen(depstring); + + /* Note the extra space in ": " to avoid matching the epoch */ + if((desc = strstr(depstring, ": ")) != NULL) { + STRDUP(depend->desc, desc + 2, return NULL); + deplen = desc - depstring; + } else { + /* no description- point desc at NULL at end of string for later use */ + depend->desc = NULL; + deplen = strlen(depstring); + desc = depstring + deplen; + } /* 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. */ @@ -442,21 +455,18 @@ alpm_depend_t *_alpm_splitdep(const char *depstring) depend->mod = ALPM_DEP_MOD_EQ; version = ptr + 1; } else { - /* no version specified, leave ptr NULL and set version to NULL */ + /* no version specified, set ptr to end of string and version to NULL */ + ptr = depstring + deplen; depend->mod = ALPM_DEP_MOD_ANY; depend->version = NULL; version = NULL; } /* copy the right parts to the right places */ - if(ptr) { - STRNDUP(depend->name, depstring, ptr - depstring, return NULL); - } else { - STRDUP(depend->name, depstring, return NULL); - } + STRNDUP(depend->name, depstring, ptr - depstring, return NULL); depend->name_hash = _alpm_hash_sdbm(depend->name); if(version) { - STRDUP(depend->version, version, return NULL); + STRNDUP(depend->version, version, desc - version, return NULL); } return depend; @@ -468,8 +478,9 @@ alpm_depend_t *_alpm_dep_dup(const alpm_depend_t *dep) CALLOC(newdep, 1, sizeof(alpm_depend_t), return NULL); STRDUP(newdep->name, dep->name, return NULL); - newdep->name_hash = dep->name_hash; STRDUP(newdep->version, dep->version, return NULL); + STRDUP(newdep->desc, dep->desc, return NULL); + newdep->name_hash = dep->name_hash; newdep->mod = dep->mod; return newdep; @@ -639,14 +650,14 @@ static alpm_pkg_t *resolvedep(alpm_handle_t *handle, alpm_depend_t *dep, count = alpm_list_count(providers); if(count >= 1) { /* default to first provider if there is no QUESTION callback */ - int index = 0; + int idx = 0; if(count > 1) { /* if there is more than one provider, we ask the user */ QUESTION(handle, ALPM_QUESTION_SELECT_PROVIDER, - providers, dep, NULL, &index); + providers, dep, NULL, &idx); } - if(index >= 0 && index < count) { - alpm_list_t *nth = alpm_list_nth(providers, index); + if(idx >= 0 && idx < count) { + alpm_list_t *nth = alpm_list_nth(providers, idx); alpm_pkg_t *pkg = nth->data; alpm_list_free(providers); return pkg; @@ -711,7 +722,7 @@ alpm_pkg_t SYMEXPORT *alpm_find_dbs_satisfier(alpm_handle_t *handle, */ int _alpm_resolvedeps(alpm_handle_t *handle, alpm_list_t *localpkgs, alpm_pkg_t *pkg, alpm_list_t *preferred, alpm_list_t **packages, - alpm_list_t *remove, alpm_list_t **data) + alpm_list_t *rem, alpm_list_t **data) { int ret = 0; alpm_list_t *i, *j; @@ -734,7 +745,7 @@ int _alpm_resolvedeps(alpm_handle_t *handle, alpm_list_t *localpkgs, for(i = alpm_list_last(*packages); i; i = i->next) { alpm_pkg_t *tpkg = i->data; targ = alpm_list_add(NULL, tpkg); - deps = alpm_checkdeps(handle, localpkgs, remove, targ, 0); + deps = alpm_checkdeps(handle, localpkgs, rem, targ, 0); alpm_list_free(targ); for(j = deps; j; j = j->next) { @@ -792,7 +803,7 @@ int _alpm_resolvedeps(alpm_handle_t *handle, alpm_list_t *localpkgs, */ char SYMEXPORT *alpm_dep_compute_string(const alpm_depend_t *dep) { - const char *name, *opr, *ver; + const char *name, *opr, *ver, *desc_delim, *desc; char *str; size_t len; @@ -834,12 +845,21 @@ char SYMEXPORT *alpm_dep_compute_string(const alpm_depend_t *dep) ver = ""; } + if(dep->desc) { + desc_delim = ": "; + desc = dep->desc; + } else { + desc_delim = ""; + desc = ""; + } + /* we can always compute len and print the string like this because opr * and ver will be empty when ALPM_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; + len = strlen(name) + strlen(opr) + strlen(ver) + + strlen(desc_delim) + strlen(desc) + 1; MALLOC(str, len, return NULL); - snprintf(str, len, "%s%s%s", name, opr, ver); + snprintf(str, len, "%s%s%s%s%s", name, opr, ver, desc_delim, desc); return str; } diff --git a/lib/libalpm/deps.h b/lib/libalpm/deps.h index ce25bda6..c8e1bc3d 100644 --- a/lib/libalpm/deps.h +++ b/lib/libalpm/deps.h @@ -1,7 +1,7 @@ /* * deps.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org> diff --git a/lib/libalpm/diskspace.c b/lib/libalpm/diskspace.c index 45908b22..2582c4c3 100644 --- a/lib/libalpm/diskspace.c +++ b/lib/libalpm/diskspace.c @@ -17,8 +17,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdio.h> #include <errno.h> @@ -60,6 +58,37 @@ static int mount_point_cmp(const void *p1, const void *p2) return -strcmp(mp1->mount_dir, mp2->mount_dir); } +static void mount_point_list_free(alpm_list_t *mount_points) +{ + alpm_list_t *i; + + for(i = mount_points; i; i = i->next) { + alpm_mountpoint_t *data = i->data; + FREE(data->mount_dir); + } + FREELIST(mount_points); +} + +static int mount_point_load_fsinfo(alpm_handle_t *handle, alpm_mountpoint_t *mountpoint) +{ +#if defined(HAVE_GETMNTENT) + /* grab the filesystem usage */ + if(statvfs(mountpoint->mount_dir, &(mountpoint->fsp)) != 0) { + _alpm_log(handle, ALPM_LOG_WARNING, + _("could not get filesystem information for %s: %s\n"), + mountpoint->mount_dir, strerror(errno)); + mountpoint->fsinfo_loaded = MOUNT_FSINFO_FAIL; + return -1; + } + + _alpm_log(handle, ALPM_LOG_DEBUG, "loading fsinfo for %s\n", mountpoint->mount_dir); + mountpoint->read_only = mountpoint->fsp.f_flag & ST_RDONLY; + mountpoint->fsinfo_loaded = MOUNT_FSINFO_LOADED; +#endif + + return 0; +} + static alpm_list_t *mount_point_list(alpm_handle_t *handle) { alpm_list_t *mount_points = NULL, *ptr; @@ -73,28 +102,15 @@ static alpm_list_t *mount_point_list(alpm_handle_t *handle) fp = setmntent(MOUNTED, "r"); if(fp == NULL) { + _alpm_log(handle, ALPM_LOG_ERROR, _("could not open file: %s: %s\n"), + MOUNTED, strerror(errno)); return NULL; } while((mnt = getmntent(fp))) { - struct statvfs fsp; - if(!mnt) { - _alpm_log(handle, ALPM_LOG_WARNING, - _("could not get filesystem information\n")); - continue; - } - if(statvfs(mnt->mnt_dir, &fsp) != 0) { - _alpm_log(handle, ALPM_LOG_WARNING, - _("could not get filesystem information for %s: %s\n"), - mnt->mnt_dir, strerror(errno)); - continue; - } - CALLOC(mp, 1, sizeof(alpm_mountpoint_t), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); mp->mount_dir = strdup(mnt->mnt_dir); mp->mount_dir_len = strlen(mp->mount_dir); - memcpy(&(mp->fsp), &fsp, sizeof(struct statvfs)); - mp->read_only = fsp.f_flag & ST_RDONLY; mount_points = alpm_list_add(mount_points, mp); } @@ -109,23 +125,15 @@ static alpm_list_t *mount_point_list(alpm_handle_t *handle) fp = fopen("/etc/mnttab", "r"); if(fp == NULL) { + _alpm_log(handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), + "/etc/mnttab", strerror(errno)); return NULL; } while((ret = getmntent(fp, &mnt)) == 0) { - struct statvfs fsp; - if(statvfs(mnt->mnt_mountp, &fsp) != 0) { - _alpm_log(handle, ALPM_LOG_WARNING, - _("could not get filesystem information for %s: %s\n"), - mnt->mnt_mountp, strerror(errno)); - continue; - } - CALLOC(mp, 1, sizeof(alpm_mountpoint_t), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); mp->mount_dir = strdup(mnt->mnt_mountp); mp->mount_dir_len = strlen(mp->mount_dir); - memcpy(&(mp->fsp), &fsp, sizeof(struct statvfs)); - mp->read_only = fsp.f_flag & ST_RDONLY; mount_points = alpm_list_add(mount_points, mp); } @@ -144,6 +152,8 @@ static alpm_list_t *mount_point_list(alpm_handle_t *handle) entries = getmntinfo(&fsp, MNT_NOWAIT); if(entries < 0) { + _alpm_log(handle, ALPM_LOG_ERROR, + _("could not get filesystem information\n")); return NULL; } @@ -158,6 +168,9 @@ static alpm_list_t *mount_point_list(alpm_handle_t *handle) mp->read_only = fsp->f_flags & MNT_RDONLY; #endif + /* we don't support lazy loading on this platform */ + mp->fsinfo_loaded = MOUNT_FSINFO_LOADED; + mount_points = alpm_list_add(mount_points, mp); } #endif @@ -166,7 +179,7 @@ static alpm_list_t *mount_point_list(alpm_handle_t *handle) mount_point_cmp); for(ptr = mount_points; ptr != NULL; ptr = ptr->next) { mp = ptr->data; - _alpm_log(handle, ALPM_LOG_DEBUG, "mountpoint: %s\n", mp->mount_dir); + _alpm_log(handle, ALPM_LOG_DEBUG, "discovered mountpoint: %s\n", mp->mount_dir); } return mount_points; } @@ -215,6 +228,7 @@ static int calculate_removed_size(alpm_handle_t *handle, alpm_mountpoint_t *mp; struct stat st; char path[PATH_MAX]; + blkcnt_t remove_size; const char *filename = file->name; snprintf(path, PATH_MAX, "%s%s", handle->root, filename); @@ -233,9 +247,21 @@ static int calculate_removed_size(alpm_handle_t *handle, continue; } + /* don't check a mount that we know we can't stat */ + if(mp && mp->fsinfo_loaded == MOUNT_FSINFO_FAIL) { + continue; + } + + /* lazy load filesystem info */ + if(mp->fsinfo_loaded == MOUNT_FSINFO_UNLOADED) { + if(mount_point_load_fsinfo(handle, mp) < 0) { + continue; + } + } + /* the addition of (divisor - 1) performs ceil() with integer division */ - mp->blocks_needed -= - (st.st_size + mp->fsp.f_bsize - 1) / mp->fsp.f_bsize; + remove_size = (st.st_size + mp->fsp.f_bsize - 1) / mp->fsp.f_bsize; + mp->blocks_needed -= remove_size; mp->used |= USED_REMOVE; } @@ -256,6 +282,7 @@ static int calculate_installed_size(alpm_handle_t *handle, const alpm_file_t *file = filelist->files + i; alpm_mountpoint_t *mp; char path[PATH_MAX]; + blkcnt_t install_size; const char *filename = file->name; /* libarchive reports these as zero size anyways */ @@ -279,15 +306,108 @@ static int calculate_installed_size(alpm_handle_t *handle, continue; } + /* don't check a mount that we know we can't stat */ + if(mp && mp->fsinfo_loaded == MOUNT_FSINFO_FAIL) { + continue; + } + + /* lazy load filesystem info */ + if(mp->fsinfo_loaded == MOUNT_FSINFO_UNLOADED) { + if(mount_point_load_fsinfo(handle, mp) < 0) { + continue; + } + } + /* the addition of (divisor - 1) performs ceil() with integer division */ - mp->blocks_needed += - (file->size + mp->fsp.f_bsize - 1) / mp->fsp.f_bsize; + install_size = (file->size + mp->fsp.f_bsize - 1) / mp->fsp.f_bsize; + mp->blocks_needed += install_size; mp->used |= USED_INSTALL; } return 0; } +static int check_mountpoint(alpm_handle_t *handle, alpm_mountpoint_t *mp) +{ + /* cushion is roughly min(5% capacity, 20MiB) */ + fsblkcnt_t fivepc = (mp->fsp.f_blocks / 20) + 1; + fsblkcnt_t twentymb = (20 * 1024 * 1024 / mp->fsp.f_bsize) + 1; + fsblkcnt_t cushion = fivepc < twentymb ? fivepc : twentymb; + blkcnt_t needed = mp->max_blocks_needed + cushion; + + _alpm_log(handle, ALPM_LOG_DEBUG, + "partition %s, needed %jd, cushion %ju, free %ju\n", + mp->mount_dir, (intmax_t)mp->max_blocks_needed, + (uintmax_t)cushion, (uintmax_t)mp->fsp.f_bfree); + if(needed >= 0 && (fsblkcnt_t)needed > mp->fsp.f_bfree) { + _alpm_log(handle, ALPM_LOG_ERROR, + _("Partition %s too full: %jd blocks needed, %jd blocks free\n"), + mp->mount_dir, (intmax_t)needed, (uintmax_t)mp->fsp.f_bfree); + return 1; + } + return 0; +} + +int _alpm_check_downloadspace(alpm_handle_t *handle, const char *cachedir, + size_t num_files, off_t *file_sizes) +{ + alpm_list_t *mount_points; + alpm_mountpoint_t *cachedir_mp; + char resolved_cachedir[PATH_MAX]; + size_t j; + int error = 0; + + /* resolve the cachedir path to ensure we check the right mountpoint. We + * handle failures silently, and continue to use the possibly unresolved + * path. */ + if(realpath(cachedir, resolved_cachedir) != NULL) { + cachedir = resolved_cachedir; + } + + mount_points = mount_point_list(handle); + if(mount_points == NULL) { + _alpm_log(handle, ALPM_LOG_ERROR, _("could not determine filesystem mount points\n")); + return -1; + } + + cachedir_mp = match_mount_point(mount_points, cachedir); + if(cachedir_mp == NULL) { + _alpm_log(handle, ALPM_LOG_ERROR, _("could not determine cachedir mount point %s\n"), + cachedir); + error = 1; + goto finish; + } + + if(cachedir_mp->fsinfo_loaded == MOUNT_FSINFO_UNLOADED) { + if(mount_point_load_fsinfo(handle, cachedir_mp)) { + error = 1; + goto finish; + } + } + + /* there's no need to check for a R/O mounted filesystem here, as + * _alpm_filecache_setup will never give us a non-writable directory */ + + /* round up the size of each file to the nearest block and accumulate */ + for(j = 0; j < num_files; j++) { + cachedir_mp->max_blocks_needed += (file_sizes[j] + cachedir_mp->fsp.f_bsize + 1) / + cachedir_mp->fsp.f_bsize; + } + + if(check_mountpoint(handle, cachedir_mp)) { + error = 1; + } + +finish: + mount_point_list_free(mount_points); + + if(error) { + RET_ERR(handle, ALPM_ERR_DISK_SPACE, -1); + } + + return 0; +} + int _alpm_check_diskspace(alpm_handle_t *handle) { alpm_list_t *mount_points, *i; @@ -356,32 +476,13 @@ int _alpm_check_diskspace(alpm_handle_t *handle) _alpm_log(handle, ALPM_LOG_ERROR, _("Partition %s is mounted read only\n"), data->mount_dir); error = 1; - } else if(data->used & USED_INSTALL) { - /* cushion is roughly min(5% capacity, 20MiB) */ - fsblkcnt_t fivepc = (data->fsp.f_blocks / 20) + 1; - fsblkcnt_t twentymb = (20 * 1024 * 1024 / data->fsp.f_bsize) + 1; - fsblkcnt_t cushion = fivepc < twentymb ? fivepc : twentymb; - blkcnt_t needed = data->max_blocks_needed + cushion; - - _alpm_log(handle, ALPM_LOG_DEBUG, - "partition %s, needed %jd, cushion %ju, free %ju\n", - data->mount_dir, (intmax_t)data->max_blocks_needed, - (uintmax_t)cushion, (uintmax_t)data->fsp.f_bfree); - if(needed >= 0 && (fsblkcnt_t)needed > data->fsp.f_bfree) { - _alpm_log(handle, ALPM_LOG_ERROR, - _("Partition %s too full: %jd blocks needed, %jd blocks free\n"), - data->mount_dir, (intmax_t)needed, (uintmax_t)data->fsp.f_bfree); - error = 1; - } + } else if(data->used & USED_INSTALL && check_mountpoint(handle, data)) { + error = 1; } } finish: - for(i = mount_points; i; i = i->next) { - alpm_mountpoint_t *data = i->data; - FREE(data->mount_dir); - } - FREELIST(mount_points); + mount_point_list_free(mount_points); if(error) { RET_ERR(handle, ALPM_ERR_DISK_SPACE, -1); diff --git a/lib/libalpm/diskspace.h b/lib/libalpm/diskspace.h index 5944bb17..591d9337 100644 --- a/lib/libalpm/diskspace.h +++ b/lib/libalpm/diskspace.h @@ -1,7 +1,7 @@ /* * diskspace.h * - * Copyright (c) 2010-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2010-2012 Pacman Development Team <pacman-dev@archlinux.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,6 +37,12 @@ enum mount_used_level { USED_INSTALL = (1 << 1), }; +enum mount_fsinfo { + MOUNT_FSINFO_UNLOADED = 0, + MOUNT_FSINFO_LOADED, + MOUNT_FSINFO_FAIL, +}; + typedef struct __alpm_mountpoint_t { /* mount point information */ char *mount_dir; @@ -46,10 +52,13 @@ typedef struct __alpm_mountpoint_t { blkcnt_t max_blocks_needed; enum mount_used_level used; int read_only; + enum mount_fsinfo fsinfo_loaded; FSSTATSTYPE fsp; } alpm_mountpoint_t; int _alpm_check_diskspace(alpm_handle_t *handle); +int _alpm_check_downloadspace(alpm_handle_t *handle, const char *cachedir, + size_t num_files, off_t *file_sizes); #endif /* _ALPM_DISKSPACE_H */ diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c index c1f54f02..6aaff1d2 100644 --- a/lib/libalpm/dload.c +++ b/lib/libalpm/dload.c @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <stdio.h> #include <errno.h> @@ -324,7 +322,7 @@ static void curl_set_handle_opts(struct dload_payload *payload, } } -static void mask_signal(int signal, void (*handler)(int), +static void mask_signal(int signum, void (*handler)(int), struct sigaction *origaction) { struct sigaction newaction; @@ -333,13 +331,13 @@ static void mask_signal(int signal, void (*handler)(int), sigemptyset(&newaction.sa_mask); newaction.sa_flags = 0; - sigaction(signal, NULL, origaction); - sigaction(signal, &newaction, NULL); + sigaction(signum, NULL, origaction); + sigaction(signum, &newaction, NULL); } -static void unmask_signal(int signal, struct sigaction *sa) +static void unmask_signal(int signum, struct sigaction *sa) { - sigaction(signal, sa, NULL); + sigaction(signum, sa, NULL); } static FILE *create_tempfile(struct dload_payload *payload, const char *localpath) @@ -357,9 +355,7 @@ static FILE *create_tempfile(struct dload_payload *payload, const char *localpat fchmod(fd, ~(_getumask()) & 0666) || !(fp = fdopen(fd, payload->tempfile_openmode))) { unlink(randpath); - if(fd >= 0) { - close(fd); - } + CLOSE(fd); _alpm_log(payload->handle, ALPM_LOG_ERROR, _("failed to create temporary file for download\n")); return NULL; @@ -432,6 +428,10 @@ static int curl_download_internal(struct dload_payload *payload, if(localf == NULL) { localf = fopen(payload->tempfile_name, payload->tempfile_openmode); if(localf == NULL) { + handle->pm_errno = ALPM_ERR_RETRIEVE; + _alpm_log(handle, ALPM_LOG_ERROR, + _("could not open file %s: %s\n"), + payload->tempfile_name, strerror(errno)); goto cleanup; } } @@ -623,18 +623,18 @@ int _alpm_download(struct dload_payload *payload, const char *localpath, static char *filecache_find_url(alpm_handle_t *handle, const char *url) { - const char *basename = strrchr(url, '/'); + const char *filebase = strrchr(url, '/'); - if(basename == NULL) { + if(filebase == NULL) { return NULL; } - basename++; - if(basename == '\0') { + filebase++; + if(filebase == '\0') { return NULL; } - return _alpm_filecache_find(handle, basename); + return _alpm_filecache_find(handle, filebase); } /** Fetch a remote pkg. */ diff --git a/lib/libalpm/dload.h b/lib/libalpm/dload.h index f5f2cd9c..e279d564 100644 --- a/lib/libalpm/dload.h +++ b/lib/libalpm/dload.h @@ -1,7 +1,7 @@ /* * dload.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -23,8 +23,6 @@ #include "alpm_list.h" #include "alpm.h" -#include <time.h> - struct dload_payload { alpm_handle_t *handle; const char *tempfile_openmode; @@ -40,6 +38,7 @@ struct dload_payload { int allow_resume; int errors_ok; int unlink_on_fail; + alpm_list_t *servers; #ifdef HAVE_LIBCURL CURLcode curlerr; /* last error produced by curl */ #endif diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c index b3f56819..86b4efb2 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -1,7 +1,7 @@ /* * error.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #ifdef HAVE_LIBCURL #include <curl/curl.h> #endif @@ -29,12 +27,12 @@ #include "alpm.h" #include "handle.h" -enum _alpm_errno_t SYMEXPORT alpm_errno(alpm_handle_t *handle) +alpm_errno_t SYMEXPORT alpm_errno(alpm_handle_t *handle) { return handle->pm_errno; } -const char SYMEXPORT *alpm_strerror(enum _alpm_errno_t err) +const char SYMEXPORT *alpm_strerror(alpm_errno_t err) { switch(err) { /* System */ @@ -43,7 +41,7 @@ const char SYMEXPORT *alpm_strerror(enum _alpm_errno_t err) case ALPM_ERR_SYSTEM: return _("unexpected system error"); case ALPM_ERR_BADPERMS: - return _("insufficient privileges"); + return _("permission denied"); case ALPM_ERR_NOT_A_FILE: return _("could not find or read file"); case ALPM_ERR_NOT_A_DIR: diff --git a/lib/libalpm/filelist.c b/lib/libalpm/filelist.c new file mode 100644 index 00000000..f6c0ed45 --- /dev/null +++ b/lib/libalpm/filelist.c @@ -0,0 +1,137 @@ +/* + * filelist.c + * + * Copyright (c) 2012 Pacman Development Team <pacman-dev@archlinux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 <string.h> + +/* libalpm */ +#include "filelist.h" + +/* Returns the difference of the provided two lists of files. + * Pre-condition: both lists are sorted! + * When done, free the list but NOT the contained data. + */ +alpm_list_t *_alpm_filelist_difference(alpm_filelist_t *filesA, + alpm_filelist_t *filesB) +{ + alpm_list_t *ret = NULL; + size_t ctrA = 0, ctrB = 0; + + while(ctrA < filesA->count && ctrB < filesB->count) { + alpm_file_t *fileA = filesA->files + ctrA; + alpm_file_t *fileB = filesB->files + ctrB; + const char *strA = fileA->name; + const char *strB = fileB->name; + /* skip directories, we don't care about them */ + if(strA[strlen(strA)-1] == '/') { + ctrA++; + } else if(strB[strlen(strB)-1] == '/') { + ctrB++; + } else { + int cmp = strcmp(strA, strB); + if(cmp < 0) { + /* item only in filesA, qualifies as a difference */ + ret = alpm_list_add(ret, fileA); + ctrA++; + } else if(cmp > 0) { + ctrB++; + } else { + ctrA++; + ctrB++; + } + } + } + + /* ensure we have completely emptied pA */ + while(ctrA < filesA->count) { + alpm_file_t *fileA = filesA->files + ctrA; + const char *strA = fileA->name; + /* skip directories */ + if(strA[strlen(strA)-1] != '/') { + ret = alpm_list_add(ret, fileA); + } + ctrA++; + } + + return ret; +} + +/* Returns the intersection of the provided two lists of files. + * Pre-condition: both lists are sorted! + * When done, free the list but NOT the contained data. + */ +alpm_list_t *_alpm_filelist_intersection(alpm_filelist_t *filesA, + alpm_filelist_t *filesB) +{ + alpm_list_t *ret = NULL; + size_t ctrA = 0, ctrB = 0; + + while(ctrA < filesA->count && ctrB < filesB->count) { + alpm_file_t *fileA = filesA->files + ctrA; + alpm_file_t *fileB = filesB->files + ctrB; + const char *strA = fileA->name; + const char *strB = fileB->name; + /* skip directories, we don't care about them */ + if(strA[strlen(strA)-1] == '/') { + ctrA++; + } else if(strB[strlen(strB)-1] == '/') { + ctrB++; + } else { + int cmp = strcmp(strA, strB); + if(cmp < 0) { + ctrA++; + } else if(cmp > 0) { + ctrB++; + } else { + /* item in both, qualifies as an intersect */ + ret = alpm_list_add(ret, fileA); + ctrA++; + ctrB++; + } + } + } + + return ret; +} + +/* Helper function for comparing files list entries + */ +int _alpm_files_cmp(const void *f1, const void *f2) +{ + const alpm_file_t *file1 = f1; + const alpm_file_t *file2 = f2; + return strcmp(file1->name, file2->name); +} + + +alpm_file_t *alpm_filelist_contains(alpm_filelist_t *filelist, + const char *path) +{ + alpm_file_t key; + + if(!filelist) { + return NULL; + } + + key.name = (char *)path; + + return bsearch(&key, filelist->files, filelist->count, + sizeof(alpm_file_t), _alpm_files_cmp); +} + +/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/filelist.h b/lib/libalpm/filelist.h new file mode 100644 index 00000000..2d5cbc03 --- /dev/null +++ b/lib/libalpm/filelist.h @@ -0,0 +1,35 @@ +/* + * filelist.h + * + * Copyright (c) 2012 Pacman Development Team <pacman-dev@archlinux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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_FILELIST_H +#define _ALPM_FILELIST_H + +#include "alpm.h" + + +alpm_list_t *_alpm_filelist_difference(alpm_filelist_t *filesA, + alpm_filelist_t *filesB); + +alpm_list_t *_alpm_filelist_intersection(alpm_filelist_t *filesA, + alpm_filelist_t *filesB); + +int _alpm_files_cmp(const void *f1, const void *f2); + +#endif /* _ALPM_FILELIST_H */ + +/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/graph.c b/lib/libalpm/graph.c index 3a7f24b8..69be9e30 100644 --- a/lib/libalpm/graph.c +++ b/lib/libalpm/graph.c @@ -1,7 +1,7 @@ /* * graph.c - helpful graph structure and setup/teardown methods * - * Copyright (c) 2007-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2007-2012 Pacman Development Team <pacman-dev@archlinux.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,8 +17,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include "graph.h" #include "util.h" #include "log.h" diff --git a/lib/libalpm/graph.h b/lib/libalpm/graph.h index d4d134b5..463b2cd8 100644 --- a/lib/libalpm/graph.h +++ b/lib/libalpm/graph.h @@ -1,7 +1,7 @@ /* * graph.h - helpful graph structure and setup/teardown methods * - * Copyright (c) 2007-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2007-2012 Pacman Development Team <pacman-dev@archlinux.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,8 +19,6 @@ #ifndef _ALPM_GRAPH_H #define _ALPM_GRAPH_H -#include "config.h" /* ensure off_t is correct length */ - #include <sys/types.h> /* off_t */ #include "alpm_list.h" diff --git a/lib/libalpm/group.c b/lib/libalpm/group.c index 47458df2..7c3d64f7 100644 --- a/lib/libalpm/group.c +++ b/lib/libalpm/group.c @@ -1,7 +1,7 @@ /* * group.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <string.h> @@ -32,7 +30,7 @@ alpm_group_t *_alpm_group_new(const char *name) { - alpm_group_t* grp; + alpm_group_t *grp; CALLOC(grp, 1, sizeof(alpm_group_t), return NULL); STRDUP(grp->name, name, free(grp); return NULL); diff --git a/lib/libalpm/group.h b/lib/libalpm/group.h index 078c9af7..1f776ebf 100644 --- a/lib/libalpm/group.h +++ b/lib/libalpm/group.h @@ -1,7 +1,7 @@ /* * group.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index 7402be50..816162bd 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -1,7 +1,7 @@ /* * handle.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org> @@ -20,8 +20,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <errno.h> #include <stdlib.h> #include <string.h> @@ -36,6 +34,7 @@ #include "alpm_list.h" #include "util.h" #include "log.h" +#include "delta.h" #include "trans.h" #include "alpm.h" @@ -44,6 +43,7 @@ alpm_handle_t *_alpm_handle_new(void) alpm_handle_t *handle; CALLOC(handle, 1, sizeof(alpm_handle_t), return NULL); + handle->deltaratio = 0.0; return handle; } @@ -69,6 +69,8 @@ void _alpm_handle_free(alpm_handle_t *handle) curl_easy_cleanup(handle->curl); #endif + regfree(&handle->delta_regex); + /* free memory */ _alpm_trans_free(handle->trans); FREE(handle->root); @@ -251,10 +253,10 @@ const char SYMEXPORT *alpm_option_get_arch(alpm_handle_t *handle) return handle->arch; } -int SYMEXPORT alpm_option_get_usedelta(alpm_handle_t *handle) +double SYMEXPORT alpm_option_get_deltaratio(alpm_handle_t *handle) { CHECK_HANDLE(handle, return -1); - return handle->usedelta; + return handle->deltaratio; } int SYMEXPORT alpm_option_get_checkspace(alpm_handle_t *handle) @@ -263,18 +265,6 @@ int SYMEXPORT alpm_option_get_checkspace(alpm_handle_t *handle) return handle->checkspace; } -alpm_db_t SYMEXPORT *alpm_option_get_localdb(alpm_handle_t *handle) -{ - CHECK_HANDLE(handle, return NULL); - return handle->db_local; -} - -alpm_list_t SYMEXPORT *alpm_option_get_syncdbs(alpm_handle_t *handle) -{ - CHECK_HANDLE(handle, return NULL); - return handle->dbs_sync; -} - int SYMEXPORT alpm_option_set_logcb(alpm_handle_t *handle, alpm_cb_log cb) { CHECK_HANDLE(handle, return -1); @@ -339,11 +329,11 @@ static char *canonicalize_path(const char *path) { return new_path; } -enum _alpm_errno_t _alpm_set_directory_option(const char *value, +alpm_errno_t _alpm_set_directory_option(const char *value, char **storage, int must_exist) { struct stat st; - char *real = NULL; + char real[PATH_MAX]; const char *path; path = value; @@ -354,9 +344,7 @@ enum _alpm_errno_t _alpm_set_directory_option(const char *value, if(stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) { return ALPM_ERR_NOT_A_DIR; } - CALLOC(real, PATH_MAX, sizeof(char), return ALPM_ERR_MEMORY); if(!realpath(path, real)) { - free(real); return ALPM_ERR_NOT_A_DIR; } path = real; @@ -369,7 +357,6 @@ enum _alpm_errno_t _alpm_set_directory_option(const char *value, if(!*storage) { return ALPM_ERR_MEMORY; } - free(real); return 0; } @@ -596,10 +583,13 @@ int SYMEXPORT alpm_option_set_arch(alpm_handle_t *handle, const char *arch) return 0; } -int SYMEXPORT alpm_option_set_usedelta(alpm_handle_t *handle, int usedelta) +int SYMEXPORT alpm_option_set_deltaratio(alpm_handle_t *handle, double ratio) { CHECK_HANDLE(handle, return -1); - handle->usedelta = usedelta; + if(ratio < 0.0 || ratio > 2.0) { + RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1); + } + handle->deltaratio = ratio; return 0; } @@ -630,4 +620,16 @@ alpm_siglevel_t SYMEXPORT alpm_option_get_default_siglevel(alpm_handle_t *handle return handle->siglevel; } +alpm_db_t SYMEXPORT *alpm_get_localdb(alpm_handle_t *handle) +{ + CHECK_HANDLE(handle, return NULL); + return handle->db_local; +} + +alpm_list_t SYMEXPORT *alpm_get_syncdbs(alpm_handle_t *handle) +{ + CHECK_HANDLE(handle, return NULL); + return handle->dbs_sync; +} + /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index 8477dcae..c0ad6686 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -1,7 +1,7 @@ /* * handle.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -22,6 +22,7 @@ #include <stdio.h> #include <sys/types.h> +#include <regex.h> #include "alpm_list.h" #include "alpm.h" @@ -86,14 +87,18 @@ struct __alpm_handle_t { alpm_list_t *ignoregroup; /* List of groups to ignore */ /* options */ - int usesyslog; /* Use syslog instead of logfile? */ /* TODO move to frontend */ char *arch; /* Architecture of packages we should allow */ - int usedelta; /* Download deltas if possible */ + double deltaratio; /* Download deltas if possible; a ratio value */ + int usesyslog; /* Use syslog instead of logfile? */ /* TODO move to frontend */ int checkspace; /* Check disk space before installing */ alpm_siglevel_t siglevel; /* Default signature verification level */ /* error code */ - enum _alpm_errno_t pm_errno; + alpm_errno_t pm_errno; + + /* for delta parsing efficiency */ + int delta_regex_compiled; + regex_t delta_regex; }; alpm_handle_t *_alpm_handle_new(void); @@ -102,7 +107,7 @@ void _alpm_handle_free(alpm_handle_t *handle); int _alpm_handle_lock(alpm_handle_t *handle); int _alpm_handle_unlock(alpm_handle_t *handle); -enum _alpm_errno_t _alpm_set_directory_option(const char *value, +alpm_errno_t _alpm_set_directory_option(const char *value, char **storage, int must_exist); #endif /* _ALPM_HANDLE_H */ diff --git a/lib/libalpm/libalpm.pc.in b/lib/libalpm/libalpm.pc.in new file mode 100644 index 00000000..fe4e2583 --- /dev/null +++ b/lib/libalpm/libalpm.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libalpm +Description: Arch Linux package management library +URL: http://www.archlinux.org/pacman/ +Version: @VERSION@ +Cflags: -I${includedir} +Libs: -L${libdir} -lalpm +Libs.private: @LIBS@ @LIBARCHIVE_LIBS@ @LIBSSL_LIBS@ @LIBCURL_LIBS@ @GPGME_LIBS@ diff --git a/lib/libalpm/log.c b/lib/libalpm/log.c index 692ff79c..8486716e 100644 --- a/lib/libalpm/log.c +++ b/lib/libalpm/log.c @@ -1,7 +1,7 @@ /* * log.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdio.h> #include <stdarg.h> #include <errno.h> diff --git a/lib/libalpm/log.h b/lib/libalpm/log.h index a43290d8..22c3d065 100644 --- a/lib/libalpm/log.h +++ b/lib/libalpm/log.h @@ -1,7 +1,7 @@ /* * log.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify diff --git a/lib/libalpm/md5.c b/lib/libalpm/md5.c index b4391a61..0d5ed9e0 100644 --- a/lib/libalpm/md5.c +++ b/lib/libalpm/md5.c @@ -33,33 +33,34 @@ * GPL. This is from version 1.0.0 of the library, and has been modified * as following, which may be helpful for future updates: * * remove "polarssl/config.h" include - * * change include from "polarssl/sha2.h" to "sha2.h" + * * change include from "polarssl/md5.h" to "md5.h" * * removal of HMAC code * * removal of SELF_TEST code - * * removal of ipad and opad from the md5_context struct in sha2.h + * * removal of ipad and opad from the md5_context struct in md5.h * * increase the size of buffer for performance reasons - * * various static changes + * * change 'unsigned long' to uint32_t */ #include <stdio.h> +#include <stdint.h> #include "md5.h" /* * 32-bit integer manipulation macros (little endian) */ -#ifndef GET_ULONG_LE -#define GET_ULONG_LE(n,b,i) \ +#ifndef GET_U32_LE +#define GET_U32_LE(n,b,i) \ { \ - (n) = ( (unsigned long) (b)[(i) ] ) \ - | ( (unsigned long) (b)[(i) + 1] << 8 ) \ - | ( (unsigned long) (b)[(i) + 2] << 16 ) \ - | ( (unsigned long) (b)[(i) + 3] << 24 ); \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ } #endif -#ifndef PUT_ULONG_LE -#define PUT_ULONG_LE(n,b,i) \ +#ifndef PUT_U32_LE +#define PUT_U32_LE(n,b,i) \ { \ (b)[(i) ] = (unsigned char) ( (n) ); \ (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ @@ -84,24 +85,24 @@ static void md5_starts( md5_context *ctx ) static void md5_process( md5_context *ctx, const unsigned char data[64] ) { - unsigned long X[16], A, B, C, D; - - 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 ); + uint32_t X[16], A, B, C, D; + + GET_U32_LE( X[ 0], data, 0 ); + GET_U32_LE( X[ 1], data, 4 ); + GET_U32_LE( X[ 2], data, 8 ); + GET_U32_LE( X[ 3], data, 12 ); + GET_U32_LE( X[ 4], data, 16 ); + GET_U32_LE( X[ 5], data, 20 ); + GET_U32_LE( X[ 6], data, 24 ); + GET_U32_LE( X[ 7], data, 28 ); + GET_U32_LE( X[ 8], data, 32 ); + GET_U32_LE( X[ 9], data, 36 ); + GET_U32_LE( X[10], data, 40 ); + GET_U32_LE( X[11], data, 44 ); + GET_U32_LE( X[12], data, 48 ); + GET_U32_LE( X[13], data, 52 ); + GET_U32_LE( X[14], data, 56 ); + GET_U32_LE( X[15], data, 60 ); #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) @@ -211,7 +212,7 @@ static void md5_process( md5_context *ctx, const unsigned char data[64] ) static void md5_update( md5_context *ctx, const unsigned char *input, size_t ilen ) { size_t fill; - unsigned long left; + uint32_t left; if( ilen <= 0 ) return; @@ -219,10 +220,10 @@ static void md5_update( md5_context *ctx, const unsigned char *input, size_t ile left = ctx->total[0] & 0x3F; fill = 64 - left; - ctx->total[0] += (unsigned long) ilen; + ctx->total[0] += (uint32_t) ilen; ctx->total[0] &= 0xFFFFFFFF; - if( ctx->total[0] < (unsigned long) ilen ) + if( ctx->total[0] < (uint32_t) ilen ) ctx->total[1]++; if( left && ilen >= fill ) @@ -262,16 +263,16 @@ static const unsigned char md5_padding[64] = */ static void md5_finish( md5_context *ctx, unsigned char output[16] ) { - unsigned long last, padn; - unsigned long high, low; + uint32_t last, padn; + uint32_t high, low; unsigned char msglen[8]; high = ( ctx->total[0] >> 29 ) | ( ctx->total[1] << 3 ); low = ( ctx->total[0] << 3 ); - PUT_ULONG_LE( low, msglen, 0 ); - PUT_ULONG_LE( high, msglen, 4 ); + PUT_U32_LE( low, msglen, 0 ); + PUT_U32_LE( high, msglen, 4 ); last = ctx->total[0] & 0x3F; padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); @@ -279,10 +280,10 @@ static void md5_finish( md5_context *ctx, unsigned char output[16] ) md5_update( ctx, (unsigned char *) md5_padding, padn ); md5_update( ctx, msglen, 8 ); - 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 ); + PUT_U32_LE( ctx->state[0], output, 0 ); + PUT_U32_LE( ctx->state[1], output, 4 ); + PUT_U32_LE( ctx->state[2], output, 8 ); + PUT_U32_LE( ctx->state[3], output, 12 ); } /* diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index a5ff238f..a4c3309e 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -1,7 +1,7 @@ /* * package.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2005, 2006 by Christian Hamar <krics@linuxforum.hu> @@ -21,8 +21,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <string.h> #include <sys/types.h> @@ -48,7 +46,7 @@ int SYMEXPORT alpm_pkg_free(alpm_pkg_t *pkg) ASSERT(pkg != NULL, return -1); /* Only free packages loaded in user space */ - if(pkg->origin == PKG_FROM_FILE) { + if(pkg->origin == ALPM_PKG_FROM_FILE) { _alpm_pkg_free(pkg); } @@ -64,12 +62,12 @@ int SYMEXPORT alpm_pkg_checkmd5sum(alpm_pkg_t *pkg) ASSERT(pkg != NULL, return -1); pkg->handle->pm_errno = 0; /* We only inspect packages from sync repositories */ - ASSERT(pkg->origin == PKG_FROM_SYNCDB, + ASSERT(pkg->origin == ALPM_PKG_FROM_SYNCDB, RET_ERR(pkg->handle, ALPM_ERR_WRONG_ARGS, -1)); fpath = _alpm_filecache_find(pkg->handle, pkg->filename); - retval = _alpm_test_checksum(fpath, pkg->md5sum, ALPM_CSUM_MD5); + retval = _alpm_test_checksum(fpath, pkg->md5sum, ALPM_PKG_VALIDATION_MD5SUM); if(retval == 0) { return 0; @@ -87,12 +85,13 @@ int SYMEXPORT alpm_pkg_checkmd5sum(alpm_pkg_t *pkg) * populated package structures. */ static const char *_pkg_get_desc(alpm_pkg_t *pkg) { return pkg->desc; } static const char *_pkg_get_url(alpm_pkg_t *pkg) { return pkg->url; } -static time_t _pkg_get_builddate(alpm_pkg_t *pkg) { return pkg->builddate; } -static time_t _pkg_get_installdate(alpm_pkg_t *pkg) { return pkg->installdate; } +static alpm_time_t _pkg_get_builddate(alpm_pkg_t *pkg) { return pkg->builddate; } +static alpm_time_t _pkg_get_installdate(alpm_pkg_t *pkg) { return pkg->installdate; } static const char *_pkg_get_packager(alpm_pkg_t *pkg) { return pkg->packager; } static const char *_pkg_get_arch(alpm_pkg_t *pkg) { return pkg->arch; } static off_t _pkg_get_isize(alpm_pkg_t *pkg) { return pkg->isize; } -static alpm_pkgreason_t _pkg_get_reason(alpm_pkg_t *pkg) { return pkg->reason; } +static alpm_pkgreason_t _pkg_get_reason(alpm_pkg_t *pkg) { return pkg->reason; } +static alpm_pkgvalidation_t _pkg_get_validation(alpm_pkg_t *pkg) { return pkg->validation; } static int _pkg_has_scriptlet(alpm_pkg_t *pkg) { return pkg->scriptlet; } static alpm_list_t *_pkg_get_licenses(alpm_pkg_t *pkg) { return pkg->licenses; } @@ -136,6 +135,7 @@ struct pkg_operations default_pkg_ops = { .get_arch = _pkg_get_arch, .get_isize = _pkg_get_isize, .get_reason = _pkg_get_reason, + .get_validation = _pkg_get_validation, .has_scriptlet = _pkg_has_scriptlet, .get_licenses = _pkg_get_licenses, @@ -200,14 +200,14 @@ const char SYMEXPORT *alpm_pkg_get_url(alpm_pkg_t *pkg) return pkg->ops->get_url(pkg); } -time_t SYMEXPORT alpm_pkg_get_builddate(alpm_pkg_t *pkg) +alpm_time_t SYMEXPORT alpm_pkg_get_builddate(alpm_pkg_t *pkg) { ASSERT(pkg != NULL, return -1); pkg->handle->pm_errno = 0; return pkg->ops->get_builddate(pkg); } -time_t SYMEXPORT alpm_pkg_get_installdate(alpm_pkg_t *pkg) +alpm_time_t SYMEXPORT alpm_pkg_get_installdate(alpm_pkg_t *pkg) { ASSERT(pkg != NULL, return -1); pkg->handle->pm_errno = 0; @@ -270,6 +270,13 @@ alpm_pkgreason_t SYMEXPORT alpm_pkg_get_reason(alpm_pkg_t *pkg) return pkg->ops->get_reason(pkg); } +alpm_pkgvalidation_t SYMEXPORT alpm_pkg_get_validation(alpm_pkg_t *pkg) +{ + ASSERT(pkg != NULL, return -1); + pkg->handle->pm_errno = 0; + return pkg->ops->get_validation(pkg); +} + alpm_list_t SYMEXPORT *alpm_pkg_get_licenses(alpm_pkg_t *pkg) { ASSERT(pkg != NULL, return NULL); @@ -344,7 +351,7 @@ alpm_db_t SYMEXPORT *alpm_pkg_get_db(alpm_pkg_t *pkg) { /* Sanity checks */ ASSERT(pkg != NULL, return NULL); - ASSERT(pkg->origin != PKG_FROM_FILE, return NULL); + ASSERT(pkg->origin != ALPM_PKG_FROM_FILE, return NULL); pkg->handle->pm_errno = 0; return pkg->origin_data.db; @@ -411,7 +418,7 @@ alpm_list_t SYMEXPORT *alpm_pkg_compute_requiredby(alpm_pkg_t *pkg) ASSERT(pkg != NULL, return NULL); pkg->handle->pm_errno = 0; - if(pkg->origin == PKG_FROM_FILE) { + if(pkg->origin == ALPM_PKG_FROM_FILE) { /* The sane option; search locally for things that require this. */ find_requiredby(pkg, pkg->handle->db_local, &reqs); } else { @@ -443,24 +450,24 @@ alpm_file_t *_alpm_file_copy(alpm_file_t *dest, return dest; } -/* Helper function for comparing files list entries - */ -int _alpm_files_cmp(const void *f1, const void *f2) -{ - const alpm_file_t *file1 = f1; - const alpm_file_t *file2 = f2; - return strcmp(file1->name, file2->name); -} - alpm_pkg_t *_alpm_pkg_new(void) { - alpm_pkg_t* pkg; + alpm_pkg_t *pkg; CALLOC(pkg, 1, sizeof(alpm_pkg_t), return NULL); return pkg; } +static alpm_list_t *list_depdup(alpm_list_t *old) +{ + alpm_list_t *i, *new = NULL; + for(i = old; i; i = i->next) { + new = alpm_list_add(new, _alpm_dep_dup(i->data)); + } + return new; +} + /** * Duplicate a package data struct. * @param pkg the package to duplicate @@ -509,10 +516,19 @@ int _alpm_pkg_dup(alpm_pkg_t *pkg, alpm_pkg_t **new_ptr) newpkg->reason = pkg->reason; newpkg->licenses = alpm_list_strdup(pkg->licenses); - for(i = pkg->replaces; i; i = i->next) { - newpkg->replaces = alpm_list_add(newpkg->replaces, _alpm_dep_dup(i->data)); - } + newpkg->replaces = list_depdup(pkg->replaces); newpkg->groups = alpm_list_strdup(pkg->groups); + for(i = pkg->backup; i; i = i->next) { + newpkg->backup = alpm_list_add(newpkg->backup, _alpm_backup_dup(i->data)); + } + newpkg->depends = list_depdup(pkg->depends); + newpkg->optdepends = list_depdup(pkg->optdepends); + newpkg->conflicts = list_depdup(pkg->conflicts); + newpkg->provides = list_depdup(pkg->provides); + for(i = pkg->deltas; i; i = i->next) { + newpkg->deltas = alpm_list_add(newpkg->deltas, _alpm_delta_dup(i->data)); + } + if(pkg->files.count) { size_t filenum; size_t len = sizeof(alpm_file_t) * pkg->files.count; @@ -525,27 +541,11 @@ int _alpm_pkg_dup(alpm_pkg_t *pkg, alpm_pkg_t **new_ptr) } newpkg->files.count = pkg->files.count; } - for(i = pkg->backup; i; i = i->next) { - newpkg->backup = alpm_list_add(newpkg->backup, _alpm_backup_dup(i->data)); - } - for(i = pkg->depends; i; i = i->next) { - newpkg->depends = alpm_list_add(newpkg->depends, _alpm_dep_dup(i->data)); - } - newpkg->optdepends = alpm_list_strdup(pkg->optdepends); - for(i = pkg->conflicts; i; i = i->next) { - newpkg->conflicts = alpm_list_add(newpkg->conflicts, _alpm_dep_dup(i->data)); - } - for(i = pkg->provides; i; i = i->next) { - newpkg->provides = alpm_list_add(newpkg->provides, _alpm_dep_dup(i->data)); - } - for(i = pkg->deltas; i; i = i->next) { - newpkg->deltas = alpm_list_add(newpkg->deltas, _alpm_delta_dup(i->data)); - } /* internal */ newpkg->infolevel = pkg->infolevel; newpkg->origin = pkg->origin; - if(newpkg->origin == PKG_FROM_FILE) { + if(newpkg->origin == ALPM_PKG_FROM_FILE) { newpkg->origin_data.file = strdup(pkg->origin_data.file); } else { newpkg->origin_data.db = pkg->origin_data.db; @@ -561,6 +561,12 @@ cleanup: RET_ERR(pkg->handle, ALPM_ERR_MEMORY, -1); } +static void free_deplist(alpm_list_t *deps) +{ + alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_dep_free); + alpm_list_free(deps); +} + void _alpm_pkg_free(alpm_pkg_t *pkg) { if(pkg == NULL) { @@ -579,8 +585,7 @@ void _alpm_pkg_free(alpm_pkg_t *pkg) FREE(pkg->arch); FREELIST(pkg->licenses); - alpm_list_free_inner(pkg->replaces, (alpm_list_fn_free)_alpm_dep_free); - alpm_list_free(pkg->replaces); + free_deplist(pkg->replaces); FREELIST(pkg->groups); if(pkg->files.count) { size_t i; @@ -591,27 +596,24 @@ void _alpm_pkg_free(alpm_pkg_t *pkg) } alpm_list_free_inner(pkg->backup, (alpm_list_fn_free)_alpm_backup_free); alpm_list_free(pkg->backup); - alpm_list_free_inner(pkg->depends, (alpm_list_fn_free)_alpm_dep_free); - alpm_list_free(pkg->depends); - FREELIST(pkg->optdepends); - alpm_list_free_inner(pkg->conflicts, (alpm_list_fn_free)_alpm_dep_free); - alpm_list_free(pkg->conflicts); - alpm_list_free_inner(pkg->provides, (alpm_list_fn_free)_alpm_dep_free); - alpm_list_free(pkg->provides); + free_deplist(pkg->depends); + free_deplist(pkg->optdepends); + free_deplist(pkg->conflicts); + free_deplist(pkg->provides); alpm_list_free_inner(pkg->deltas, (alpm_list_fn_free)_alpm_delta_free); alpm_list_free(pkg->deltas); alpm_list_free(pkg->delta_path); alpm_list_free(pkg->removes); - if(pkg->origin == PKG_FROM_FILE) { + if(pkg->origin == ALPM_PKG_FROM_FILE) { FREE(pkg->origin_data.file); } FREE(pkg); } /* This function should be used when removing a target from upgrade/sync target list - * Case 1: If pkg is a loaded package file (PKG_FROM_FILE), it will be freed. - * Case 2: If pkg is a pkgcache entry (PKG_FROM_CACHE), it won't be freed, + * Case 1: If pkg is a loaded package file (ALPM_PKG_FROM_FILE), it will be freed. + * Case 2: If pkg is a pkgcache entry (ALPM_PKG_FROM_CACHE), it won't be freed, * only the transaction specific fields of pkg will be freed. */ void _alpm_pkg_free_trans(alpm_pkg_t *pkg) @@ -620,7 +622,7 @@ void _alpm_pkg_free_trans(alpm_pkg_t *pkg) return; } - if(pkg->origin == PKG_FROM_FILE) { + if(pkg->origin == ALPM_PKG_FROM_FILE) { _alpm_pkg_free(pkg); return; } @@ -690,14 +692,14 @@ int _alpm_pkg_should_ignore(alpm_handle_t *handle, alpm_pkg_t *pkg) alpm_list_t *groups = NULL; /* first see if the package is ignored */ - if(alpm_list_find_str(handle->ignorepkg, pkg->name)) { + if(alpm_list_find(handle->ignorepkg, pkg->name, _alpm_fnmatch)) { return 1; } /* next see if the package is in a group that is ignored */ - for(groups = handle->ignoregroup; groups; groups = groups->next) { + for(groups = alpm_pkg_get_groups(pkg); groups; groups = groups->next) { char *grp = groups->data; - if(alpm_list_find_str(alpm_pkg_get_groups(pkg), grp)) { + if(alpm_list_find(handle->ignoregroup, grp, _alpm_fnmatch)) { return 1; } } diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h index eff7d898..313fe9dd 100644 --- a/lib/libalpm/package.h +++ b/lib/libalpm/package.h @@ -1,7 +1,7 @@ /* * package.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2006 by David Kimpe <dnaku@frugalware.org> @@ -24,10 +24,7 @@ #ifndef _ALPM_PACKAGE_H #define _ALPM_PACKAGE_H -#include "config.h" /* ensure off_t is correct length */ - #include <sys/types.h> /* off_t */ -#include <time.h> /* time_t */ #include "alpm.h" #include "backup.h" @@ -44,12 +41,13 @@ struct pkg_operations { const char *(*get_desc) (alpm_pkg_t *); const char *(*get_url) (alpm_pkg_t *); - time_t (*get_builddate) (alpm_pkg_t *); - time_t (*get_installdate) (alpm_pkg_t *); + alpm_time_t (*get_builddate) (alpm_pkg_t *); + alpm_time_t (*get_installdate) (alpm_pkg_t *); const char *(*get_packager) (alpm_pkg_t *); const char *(*get_arch) (alpm_pkg_t *); off_t (*get_isize) (alpm_pkg_t *); alpm_pkgreason_t (*get_reason) (alpm_pkg_t *); + alpm_pkgvalidation_t (*get_validation) (alpm_pkg_t *); int (*has_scriptlet) (alpm_pkg_t *); alpm_list_t *(*get_licenses) (alpm_pkg_t *); @@ -89,8 +87,8 @@ struct __alpm_pkg_t { char *base64_sig; char *arch; - time_t builddate; - time_t installdate; + alpm_time_t builddate; + alpm_time_t installdate; off_t size; off_t isize; @@ -99,6 +97,7 @@ struct __alpm_pkg_t { int scriptlet; alpm_pkgreason_t reason; + alpm_pkgvalidation_t validation; alpm_dbinfrq_t infolevel; alpm_pkgfrom_t origin; /* origin == PKG_FROM_FILE, use pkg->origin_data.file @@ -127,16 +126,15 @@ struct __alpm_pkg_t { }; alpm_file_t *_alpm_file_copy(alpm_file_t *dest, const alpm_file_t *src); -int _alpm_files_cmp(const void *f1, const void *f2); -alpm_pkg_t* _alpm_pkg_new(void); +alpm_pkg_t *_alpm_pkg_new(void); int _alpm_pkg_dup(alpm_pkg_t *pkg, alpm_pkg_t **new_ptr); void _alpm_pkg_free(alpm_pkg_t *pkg); void _alpm_pkg_free_trans(alpm_pkg_t *pkg); int _alpm_pkg_validate_internal(alpm_handle_t *handle, const char *pkgfile, alpm_pkg_t *syncpkg, alpm_siglevel_t level, - alpm_siglist_t **sigdata); + alpm_siglist_t **sigdata, alpm_pkgvalidation_t *validation); alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, const char *pkgfile, int full); diff --git a/lib/libalpm/pkghash.c b/lib/libalpm/pkghash.c index 963ba25e..7b388004 100644 --- a/lib/libalpm/pkghash.c +++ b/lib/libalpm/pkghash.c @@ -1,7 +1,7 @@ /* * pkghash.c * - * Copyright (c) 2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2011-2012 Pacman Development Team <pacman-dev@archlinux.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,42 +26,51 @@ * * The maximum table size is the last prime under 1,000,000. That is * more than an order of magnitude greater than the number of packages - * in any Linux distribution. + * in any Linux distribution, and well under UINT_MAX. */ -static const size_t prime_list[] = +static const unsigned int prime_list[] = { - 11ul, 13ul, 17ul, 19ul, 23ul, 29ul, 31ul, 37ul, 41ul, 43ul, 47ul, - 53ul, 59ul, 61ul, 67ul, 71ul, 73ul, 79ul, 83ul, 89ul, 97ul, 103ul, - 109ul, 113ul, 127ul, 137ul, 139ul, 149ul, 157ul, 167ul, 179ul, 193ul, - 199ul, 211ul, 227ul, 241ul, 257ul, 277ul, 293ul, 313ul, 337ul, 359ul, - 383ul, 409ul, 439ul, 467ul, 503ul, 541ul, 577ul, 619ul, 661ul, 709ul, - 761ul, 823ul, 887ul, 953ul, 1031ul, 1109ul, 1193ul, 1289ul, 1381ul, - 1493ul, 1613ul, 1741ul, 1879ul, 2029ul, 2179ul, 2357ul, 2549ul, - 2753ul, 2971ul, 3209ul, 3469ul, 3739ul, 4027ul, 4349ul, 4703ul, - 5087ul, 5503ul, 5953ul, 6427ul, 6949ul, 7517ul, 8123ul, 8783ul, - 9497ul, 10273ul, 11113ul, 12011ul, 12983ul, 14033ul, 15173ul, - 16411ul, 17749ul, 19183ul, 20753ul, 22447ul, 24281ul, 26267ul, - 28411ul, 30727ul, 33223ul, 35933ul, 38873ul, 42043ul, 45481ul, - 49201ul, 53201ul, 57557ul, 62233ul, 67307ul, 72817ul, 78779ul, - 85229ul, 92203ul, 99733ul, 107897ul, 116731ul, 126271ul, 136607ul, - 147793ul, 159871ul, 172933ul, 187091ul, 202409ul, 218971ul, 236897ul, - 256279ul, 277261ul, 299951ul, 324503ul, 351061ul, 379787ul, 410857ul, - 444487ul, 480881ul, 520241ul, 562841ul, 608903ul, 658753ul, 712697ul, - 771049ul, 834181ul, 902483ul, 976369ul + 11u, 13u, 17u, 19u, 23u, 29u, 31u, 37u, 41u, 43u, 47u, + 53u, 59u, 61u, 67u, 71u, 73u, 79u, 83u, 89u, 97u, 103u, + 109u, 113u, 127u, 137u, 139u, 149u, 157u, 167u, 179u, 193u, + 199u, 211u, 227u, 241u, 257u, 277u, 293u, 313u, 337u, 359u, + 383u, 409u, 439u, 467u, 503u, 541u, 577u, 619u, 661u, 709u, + 761u, 823u, 887u, 953u, 1031u, 1109u, 1193u, 1289u, 1381u, + 1493u, 1613u, 1741u, 1879u, 2029u, 2179u, 2357u, 2549u, + 2753u, 2971u, 3209u, 3469u, 3739u, 4027u, 4349u, 4703u, + 5087u, 5503u, 5953u, 6427u, 6949u, 7517u, 8123u, 8783u, + 9497u, 10273u, 11113u, 12011u, 12983u, 14033u, 15173u, + 16411u, 17749u, 19183u, 20753u, 22447u, 24281u, 26267u, + 28411u, 30727u, 33223u, 35933u, 38873u, 42043u, 45481u, + 49201u, 53201u, 57557u, 62233u, 67307u, 72817u, 78779u, + 85229u, 92203u, 99733u, 107897u, 116731u, 126271u, 136607u, + 147793u, 159871u, 172933u, 187091u, 202409u, 218971u, 236897u, + 256279u, 277261u, 299951u, 324503u, 351061u, 379787u, 410857u, + 444487u, 480881u, 520241u, 562841u, 608903u, 658753u, 712697u, + 771049u, 834181u, 902483u, 976369u }; -/* Allocate a hash table with at least "size" buckets */ -alpm_pkghash_t *_alpm_pkghash_create(size_t size) +/* How far forward do we look when linear probing for a spot? */ +static const unsigned int stride = 1; +/* What is the maximum load percentage of our hash table? */ +static const double max_hash_load = 0.68; +/* Initial load percentage given a certain size */ +static const double initial_hash_load = 0.58; + +/* Allocate a hash table with space for at least "size" elements */ +alpm_pkghash_t *_alpm_pkghash_create(unsigned int size) { alpm_pkghash_t *hash = NULL; - size_t i, loopsize; + unsigned int i, loopsize; CALLOC(hash, 1, sizeof(alpm_pkghash_t), return NULL); + size = size / initial_hash_load + 1; loopsize = sizeof(prime_list) / sizeof(*prime_list); for(i = 0; i < loopsize; i++) { if(prime_list[i] > size) { hash->buckets = prime_list[i]; + hash->limit = hash->buckets * max_hash_load; break; } } @@ -78,15 +87,19 @@ alpm_pkghash_t *_alpm_pkghash_create(size_t size) return hash; } -static size_t get_hash_position(unsigned long name_hash, alpm_pkghash_t *hash) +static unsigned int get_hash_position(unsigned long name_hash, + alpm_pkghash_t *hash) { - size_t position; + unsigned int position; position = name_hash % hash->buckets; /* collision resolution using open addressing with linear probing */ while(hash->hash_table[position] != NULL) { - position = (position + 1) % hash->buckets; + position += stride; + while(position >= hash->buckets) { + position -= hash->buckets; + } } return position; @@ -96,7 +109,7 @@ static size_t get_hash_position(unsigned long name_hash, alpm_pkghash_t *hash) static alpm_pkghash_t *rehash(alpm_pkghash_t *oldhash) { alpm_pkghash_t *newhash; - size_t newsize, position, i; + unsigned int newsize, i; /* Hash tables will need resized in two cases: * - adding packages to the local database @@ -129,8 +142,7 @@ static alpm_pkghash_t *rehash(alpm_pkghash_t *oldhash) for(i = 0; i < oldhash->buckets; i++) { if(oldhash->hash_table[i] != NULL) { alpm_pkg_t *package = oldhash->hash_table[i]->data; - - position = get_hash_position(package->name_hash, newhash); + unsigned int position = get_hash_position(package->name_hash, newhash); newhash->hash_table[position] = oldhash->hash_table[i]; oldhash->hash_table[i] = NULL; @@ -144,16 +156,17 @@ static alpm_pkghash_t *rehash(alpm_pkghash_t *oldhash) return newhash; } -static alpm_pkghash_t *pkghash_add_pkg(alpm_pkghash_t *hash, alpm_pkg_t *pkg, int sorted) +static alpm_pkghash_t *pkghash_add_pkg(alpm_pkghash_t *hash, alpm_pkg_t *pkg, + int sorted) { alpm_list_t *ptr; - size_t position; + unsigned int position; if(pkg == NULL || hash == NULL) { return hash; } - if((hash->entries + 1) / MAX_HASH_LOAD > hash->buckets) { + if(hash->entries >= hash->limit) { hash = rehash(hash); } @@ -189,7 +202,8 @@ alpm_pkghash_t *_alpm_pkghash_add_sorted(alpm_pkghash_t *hash, alpm_pkg_t *pkg) return pkghash_add_pkg(hash, pkg, 1); } -static size_t move_one_entry(alpm_pkghash_t *hash, size_t start, size_t end) +static unsigned int move_one_entry(alpm_pkghash_t *hash, + unsigned int start, unsigned int end) { /* Iterate backwards from 'end' to 'start', seeing if any of the items * would hash to 'start'. If we find one, we move it there and break. If @@ -201,7 +215,7 @@ static size_t move_one_entry(alpm_pkghash_t *hash, size_t start, size_t end) while(end != start) { alpm_list_t *i = hash->hash_table[end]; alpm_pkg_t *info = i->data; - size_t new_position = get_hash_position(info->name_hash, hash); + unsigned int new_position = get_hash_position(info->name_hash, hash); if(new_position == start) { hash->hash_table[start] = i; @@ -212,7 +226,7 @@ static size_t move_one_entry(alpm_pkghash_t *hash, size_t start, size_t end) /* the odd math ensures we are always positive, e.g. * e.g. (0 - 1) % 47 == -1 * e.g. (47 + 0 - 1) % 47 == 46 */ - end = (hash->buckets + end - 1) % hash->buckets; + end = (hash->buckets + end - stride) % hash->buckets; } return end; } @@ -230,7 +244,7 @@ alpm_pkghash_t *_alpm_pkghash_remove(alpm_pkghash_t *hash, alpm_pkg_t *pkg, alpm_pkg_t **data) { alpm_list_t *i; - size_t position; + unsigned int position; if(data) { *data = NULL; @@ -246,7 +260,7 @@ alpm_pkghash_t *_alpm_pkghash_remove(alpm_pkghash_t *hash, alpm_pkg_t *pkg, if(info->name_hash == pkg->name_hash && strcmp(info->name, pkg->name) == 0) { - size_t stop, prev; + unsigned int stop, prev; /* remove from list and hash */ hash->list = alpm_list_remove_item(hash->list, i); @@ -260,11 +274,17 @@ alpm_pkghash_t *_alpm_pkghash_remove(alpm_pkghash_t *hash, alpm_pkg_t *pkg, /* Potentially move entries following removed entry to keep open * addressing collision resolution working. We start by finding the * next null bucket to know how far we have to look. */ - stop = (position + 1) % hash->buckets; + stop = position + stride; + while(stop >= hash->buckets) { + stop -= hash->buckets; + } while(hash->hash_table[stop] != NULL && stop != position) { - stop = (stop + 1) % hash->buckets; + stop += stride; + while(stop >= hash->buckets) { + stop -= hash->buckets; + } } - stop = (hash->buckets + stop - 1) % hash->buckets; + stop = (hash->buckets + stop - stride) % hash->buckets; /* We now search backwards from stop to position. If we find an * item that now hashes to position, we will move it, and then try @@ -277,7 +297,10 @@ alpm_pkghash_t *_alpm_pkghash_remove(alpm_pkghash_t *hash, alpm_pkg_t *pkg, return hash; } - position = (position + 1) % hash->buckets; + position += stride; + while(position >= hash->buckets) { + position -= hash->buckets; + } } return hash; @@ -285,8 +308,8 @@ alpm_pkghash_t *_alpm_pkghash_remove(alpm_pkghash_t *hash, alpm_pkg_t *pkg, void _alpm_pkghash_free(alpm_pkghash_t *hash) { - size_t i; if(hash != NULL) { + unsigned int i; for(i = 0; i < hash->buckets; i++) { free(hash->hash_table[i]); } @@ -299,7 +322,7 @@ alpm_pkg_t *_alpm_pkghash_find(alpm_pkghash_t *hash, const char *name) { alpm_list_t *lp; unsigned long name_hash; - size_t position; + unsigned int position; if(name == NULL || hash == NULL) { return NULL; @@ -316,7 +339,10 @@ alpm_pkg_t *_alpm_pkghash_find(alpm_pkghash_t *hash, const char *name) return info; } - position = (position + 1) % hash->buckets; + position += stride; + while(position >= hash->buckets) { + position -= hash->buckets; + } } return NULL; diff --git a/lib/libalpm/pkghash.h b/lib/libalpm/pkghash.h index edd500e9..a2c39c7f 100644 --- a/lib/libalpm/pkghash.h +++ b/lib/libalpm/pkghash.h @@ -1,7 +1,7 @@ /* * pkghash.h * - * Copyright (c) 2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2011-2012 Pacman Development Team <pacman-dev@archlinux.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,17 +35,19 @@ struct __alpm_pkghash_t { /** data held by the hash table */ alpm_list_t **hash_table; - /** number of buckets in hash table */ - size_t buckets; - /** number of entries in hash table */ - size_t entries; /** head node of the hash table data in normal list format */ alpm_list_t *list; + /** number of buckets in hash table */ + unsigned int buckets; + /** number of entries in hash table */ + unsigned int entries; + /** max number of entries before a resize is needed */ + unsigned int limit; }; typedef struct __alpm_pkghash_t alpm_pkghash_t; -alpm_pkghash_t *_alpm_pkghash_create(size_t size); +alpm_pkghash_t *_alpm_pkghash_create(unsigned int size); alpm_pkghash_t *_alpm_pkghash_add(alpm_pkghash_t *hash, alpm_pkg_t *pkg); alpm_pkghash_t *_alpm_pkghash_add_sorted(alpm_pkghash_t *hash, alpm_pkg_t *pkg); @@ -55,6 +57,4 @@ void _alpm_pkghash_free(alpm_pkghash_t *hash); alpm_pkg_t *_alpm_pkghash_find(alpm_pkghash_t *hash, const char *name); -#define MAX_HASH_LOAD 0.7 - #endif /* _ALPM_PKGHASH_H */ diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index cc9e289d..4c549926 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -22,8 +22,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <errno.h> #include <string.h> @@ -43,8 +41,16 @@ #include "db.h" #include "deps.h" #include "handle.h" -#include "conflict.h" +#include "filelist.h" +/** + * @brief Add a package removal action to the transaction. + * + * @param handle the context handle + * @param pkg the package to uninstall + * + * @return 0 on success, -1 on error + */ int SYMEXPORT alpm_remove_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg) { const char *pkgname; @@ -75,6 +81,14 @@ int SYMEXPORT alpm_remove_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg) return 0; } +/** + * @brief Add dependencies to the removal transaction for cascading. + * + * @param handle the context handle + * @param lp list of missing dependencies caused by the removal transaction + * + * @return 0 on success, -1 on error + */ static int remove_prepare_cascade(alpm_handle_t *handle, alpm_list_t *lp) { alpm_trans_t *trans = handle->trans; @@ -107,6 +121,12 @@ static int remove_prepare_cascade(alpm_handle_t *handle, alpm_list_t *lp) return 0; } +/** + * @brief Remove needed packages from the removal transaction. + * + * @param handle the context handle + * @param lp list of missing dependencies caused by the removal transaction + */ static void remove_prepare_keep_needed(alpm_handle_t *handle, alpm_list_t *lp) { alpm_trans_t *trans = handle->trans; @@ -137,12 +157,16 @@ static void remove_prepare_keep_needed(alpm_handle_t *handle, alpm_list_t *lp) } } -/** Transaction preparation for remove actions. +/** + * @brief Transaction preparation for remove actions. + * * This functions takes a pointer to a alpm_list_t which will be * filled with a list of alpm_depmissing_t* objects representing * the packages blocking the transaction. + * * @param handle the context handle * @param data a pointer to an alpm_list_t* to fill + * * @return 0 on success, -1 on error */ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data) @@ -211,12 +235,21 @@ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data) return 0; } +/** + * @brief Check if alpm can delete a file. + * + * @param handle the context handle + * @param file file to be removed + * @param skip_remove list of files that will not be removed + * + * @return 1 if the file can be deleted, 0 if it cannot be deleted + */ static int can_remove_file(alpm_handle_t *handle, const alpm_file_t *file, alpm_list_t *skip_remove) { char filepath[PATH_MAX]; - if(alpm_list_find_str(skip_remove, file->name)) { + if(alpm_list_find(skip_remove, file->name, _alpm_fnmatch)) { /* return success because we will never actually remove this file */ return 1; } @@ -237,10 +270,26 @@ static int can_remove_file(alpm_handle_t *handle, const alpm_file_t *file, return 1; } -/* Helper function for iterating through a package's file and deleting them - * Used by _alpm_remove_commit. */ -static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, - const alpm_file_t *fileobj, alpm_list_t *skip_remove, int nosave) +/** + * @brief Unlink a package file, backing it up if necessary. + * + * @note Helper function for iterating through a package's file and deleting + * them. + * @note Used by _alpm_remove_commit. + * + * @param handle the context handle + * @param oldpkg the package being removed + * @param newpkg the package replacing \a oldpkg + * @param fileobj file to remove + * @param skip_remove list of files that shouldn't be removed + * @param nosave whether files should be backed up + * + * @return 0 on success, -1 if there was an error unlinking the file, 1 if the + * file was skipped or did not exist + */ +static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *oldpkg, + alpm_pkg_t *newpkg, const alpm_file_t *fileobj, alpm_list_t *skip_remove, + int nosave) { struct stat buf; char file[PATH_MAX]; @@ -250,7 +299,7 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, /* check the remove skip list before removing the file. * see the big comment block in db_find_fileconflicts() for an * explanation. */ - if(alpm_list_find_str(skip_remove, fileobj->name)) { + if(alpm_list_find(skip_remove, fileobj->name, _alpm_fnmatch)) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is in skip_remove, skipping removal\n", file); return 1; @@ -274,6 +323,10 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, } else if(files < 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (could not count files)\n", file); + } else if(newpkg && alpm_filelist_contains(alpm_pkg_get_files(newpkg), + fileobj->name)) { + _alpm_log(handle, ALPM_LOG_DEBUG, + "keeping directory %s (in new package)\n", file); } else { /* one last check- does any other package own this file? */ alpm_list_t *local, *local_pkgs; @@ -285,11 +338,12 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, /* we duplicated the package when we put it in the removal list, so we * so we can't use direct pointer comparison here. */ - if(_alpm_pkg_cmp(info, local_pkg) == 0) { + if(oldpkg->name_hash == local_pkg->name_hash + && strcmp(oldpkg->name, local_pkg->name) == 0) { continue; } filelist = alpm_pkg_get_files(local_pkg); - if(_alpm_filelist_contains(filelist, fileobj->name)) { + if(alpm_filelist_contains(filelist, fileobj->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (owned by %s)\n", file, local_pkg->name); found = 1; @@ -308,7 +362,7 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, } } else { /* if the file needs backup and has been modified, back it up to .pacsave */ - alpm_backup_t *backup = _alpm_needbackup(fileobj->name, info); + alpm_backup_t *backup = _alpm_needbackup(fileobj->name, oldpkg); if(backup) { if(nosave) { _alpm_log(handle, ALPM_LOG_DEBUG, "transaction is set to NOSAVE, not backing up '%s'\n", file); @@ -350,38 +404,28 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, return 0; } -int _alpm_remove_single_package(alpm_handle_t *handle, +/** + * @brief Remove a package's files, optionally skipping its replacement's + * files. + * + * @param handle the context handle + * @param oldpkg package to remove + * @param newpkg package to replace \a oldpkg (optional) + * @param targ_count current index within the transaction (1-based) + * @param pkg_count the number of packages affected by the transaction + * + * @return 0 on success, -1 if alpm lacks permission to delete some of the + * files, >0 the number of files alpm was unable to delete + */ +static int remove_package_files(alpm_handle_t *handle, alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg, size_t targ_count, size_t pkg_count) { alpm_list_t *skip_remove; - size_t filenum = 0, position = 0; - const char *pkgname = oldpkg->name; - const char *pkgver = oldpkg->version; alpm_filelist_t *filelist; size_t i; - - if(newpkg) { - _alpm_log(handle, ALPM_LOG_DEBUG, "removing old package first (%s-%s)\n", - pkgname, pkgver); - } else { - EVENT(handle, ALPM_EVENT_REMOVE_START, oldpkg, NULL); - _alpm_log(handle, ALPM_LOG_DEBUG, "removing package %s-%s\n", - pkgname, pkgver); - - /* run the pre-remove scriptlet if it exists */ - if(alpm_pkg_has_scriptlet(oldpkg) && - !(handle->trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) { - char *scriptlet = _alpm_local_db_pkgpath(handle->db_local, - oldpkg, "install"); - _alpm_runscriptlet(handle, scriptlet, "pre_remove", pkgver, NULL, 0); - free(scriptlet); - } - } - - if(handle->trans->flags & ALPM_TRANS_FLAG_DBONLY) { - goto db; - } + int err = 0; + int nosave = handle->trans->flags & ALPM_TRANS_FLAG_NOSAVE; if(newpkg) { alpm_filelist_t *newfiles; @@ -396,7 +440,7 @@ int _alpm_remove_single_package(alpm_handle_t *handle, for(b = alpm_pkg_get_backup(newpkg); b; b = b->next) { const alpm_backup_t *backup = b->data; /* safety check (fix the upgrade026 pactest) */ - if(!_alpm_filelist_contains(newfiles, backup->name)) { + if(!alpm_filelist_contains(newfiles, backup->name)) { continue; } _alpm_log(handle, ALPM_LOG_DEBUG, "adding %s to the skip_remove array\n", @@ -412,54 +456,100 @@ int _alpm_remove_single_package(alpm_handle_t *handle, alpm_file_t *file = filelist->files + i; if(!can_remove_file(handle, file, skip_remove)) { _alpm_log(handle, ALPM_LOG_DEBUG, - "not removing package '%s', can't remove all files\n", pkgname); + "not removing package '%s', can't remove all files\n", + oldpkg->name); + FREELIST(skip_remove); RET_ERR(handle, ALPM_ERR_PKG_CANT_REMOVE, -1); } - filenum++; } - _alpm_log(handle, ALPM_LOG_DEBUG, "removing %ld files\n", (unsigned long)filenum); + _alpm_log(handle, ALPM_LOG_DEBUG, "removing %zd files\n", filelist->count); if(!newpkg) { /* init progress bar, but only on true remove transactions */ - PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, pkgname, 0, + PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name, 0, pkg_count, targ_count); } /* iterate through the list backwards, unlinking files */ for(i = filelist->count; i > 0; i--) { alpm_file_t *file = filelist->files + i - 1; - int percent; - /* TODO: check return code and handle accordingly */ - unlink_file(handle, oldpkg, file, skip_remove, - handle->trans->flags & ALPM_TRANS_FLAG_NOSAVE); + if(unlink_file(handle, oldpkg, newpkg, file, skip_remove, nosave) < 0) { + err++; + } if(!newpkg) { /* update progress bar after each file */ - percent = (position * 100) / filenum; - PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, pkgname, + int percent = ((filelist->count - i) * 100) / filelist->count; + PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name, percent, pkg_count, targ_count); } - position++; } FREELIST(skip_remove); if(!newpkg) { /* set progress to 100% after we finish unlinking files */ - PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, pkgname, 100, + PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name, 100, pkg_count, targ_count); + } + + return err; +} + +/** + * @brief Remove a package from the filesystem. + * + * @param handle the context handle + * @param oldpkg package to remove + * @param newpkg package to replace \a oldpkg (optional) + * @param targ_count current index within the transaction (1-based) + * @param pkg_count the number of packages affected by the transaction + * + * @return 0 + */ +int _alpm_remove_single_package(alpm_handle_t *handle, + alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg, + size_t targ_count, size_t pkg_count) +{ + const char *pkgname = oldpkg->name; + const char *pkgver = oldpkg->version; - /* run the post-remove script if it exists */ + if(newpkg) { + _alpm_log(handle, ALPM_LOG_DEBUG, "removing old package first (%s-%s)\n", + pkgname, pkgver); + } else { + EVENT(handle, ALPM_EVENT_REMOVE_START, oldpkg, NULL); + _alpm_log(handle, ALPM_LOG_DEBUG, "removing package %s-%s\n", + pkgname, pkgver); + + /* run the pre-remove scriptlet if it exists */ if(alpm_pkg_has_scriptlet(oldpkg) && !(handle->trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) { char *scriptlet = _alpm_local_db_pkgpath(handle->db_local, oldpkg, "install"); - _alpm_runscriptlet(handle, scriptlet, "post_remove", pkgver, NULL, 0); + _alpm_runscriptlet(handle, scriptlet, "pre_remove", pkgver, NULL, 0); free(scriptlet); } } -db: + if(!(handle->trans->flags & ALPM_TRANS_FLAG_DBONLY)) { + /* TODO check returned errors if any */ + remove_package_files(handle, oldpkg, newpkg, targ_count, pkg_count); + } + + /* run the post-remove script if it exists */ + if(!newpkg && alpm_pkg_has_scriptlet(oldpkg) && + !(handle->trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) { + char *scriptlet = _alpm_local_db_pkgpath(handle->db_local, + oldpkg, "install"); + _alpm_runscriptlet(handle, scriptlet, "post_remove", pkgver, NULL, 0); + free(scriptlet); + } + + if(!newpkg) { + EVENT(handle, ALPM_EVENT_REMOVE_DONE, oldpkg, NULL); + } + /* remove the package from the database */ _alpm_log(handle, ALPM_LOG_DEBUG, "removing database entry '%s'\n", pkgname); if(_alpm_local_db_remove(handle->db_local, oldpkg) == -1) { @@ -472,14 +562,18 @@ db: pkgname); } - if(!newpkg) { - /* TODO: awesome! we're passing invalid pointers. */ - EVENT(handle, ALPM_EVENT_REMOVE_DONE, oldpkg, NULL); - } - + /* TODO: useful return values */ return 0; } +/** + * @brief Remove packages in the current transaction. + * + * @param handle the context handle + * @param run_ldconfig whether to run ld_config after removing the packages + * + * @return 0 on success, -1 if errors occurred while removing files + */ int _alpm_remove_packages(alpm_handle_t *handle, int run_ldconfig) { alpm_list_t *targ; diff --git a/lib/libalpm/remove.h b/lib/libalpm/remove.h index 251e4548..203eccb4 100644 --- a/lib/libalpm/remove.h +++ b/lib/libalpm/remove.h @@ -1,7 +1,7 @@ /* * remove.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify diff --git a/lib/libalpm/sha2.c b/lib/libalpm/sha2.c index 3632c131..366dc650 100644 --- a/lib/libalpm/sha2.c +++ b/lib/libalpm/sha2.c @@ -38,28 +38,29 @@ * * removal of SELF_TEST code * * removal of ipad and opad from the sha2_context struct in sha2.h * * increase the size of buffer for performance reasons - * * various static changes + * * change 'unsigned long' to uint32_t */ #include <stdio.h> +#include <stdint.h> #include "sha2.h" /* * 32-bit integer manipulation macros (big endian) */ -#ifndef GET_ULONG_BE -#define GET_ULONG_BE(n,b,i) \ +#ifndef GET_U32_BE +#define GET_U32_BE(n,b,i) \ { \ - (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ - | ( (unsigned long) (b)[(i) + 1] << 16 ) \ - | ( (unsigned long) (b)[(i) + 2] << 8 ) \ - | ( (unsigned long) (b)[(i) + 3] ); \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ } #endif -#ifndef PUT_ULONG_BE -#define PUT_ULONG_BE(n,b,i) \ +#ifndef PUT_U32_BE +#define PUT_U32_BE(n,b,i) \ { \ (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ @@ -106,25 +107,25 @@ static void sha2_starts( sha2_context *ctx, int is224 ) static void sha2_process( sha2_context *ctx, const unsigned char data[64] ) { - unsigned long temp1, temp2, W[64]; - unsigned long A, B, C, D, E, F, G, H; - - GET_ULONG_BE( W[ 0], data, 0 ); - GET_ULONG_BE( W[ 1], data, 4 ); - GET_ULONG_BE( W[ 2], data, 8 ); - GET_ULONG_BE( W[ 3], data, 12 ); - GET_ULONG_BE( W[ 4], data, 16 ); - GET_ULONG_BE( W[ 5], data, 20 ); - GET_ULONG_BE( W[ 6], data, 24 ); - GET_ULONG_BE( W[ 7], data, 28 ); - GET_ULONG_BE( W[ 8], data, 32 ); - GET_ULONG_BE( W[ 9], data, 36 ); - GET_ULONG_BE( W[10], data, 40 ); - GET_ULONG_BE( W[11], data, 44 ); - GET_ULONG_BE( W[12], data, 48 ); - GET_ULONG_BE( W[13], data, 52 ); - GET_ULONG_BE( W[14], data, 56 ); - GET_ULONG_BE( W[15], data, 60 ); + uint32_t temp1, temp2, W[64]; + uint32_t A, B, C, D, E, F, G, H; + + GET_U32_BE( W[ 0], data, 0 ); + GET_U32_BE( W[ 1], data, 4 ); + GET_U32_BE( W[ 2], data, 8 ); + GET_U32_BE( W[ 3], data, 12 ); + GET_U32_BE( W[ 4], data, 16 ); + GET_U32_BE( W[ 5], data, 20 ); + GET_U32_BE( W[ 6], data, 24 ); + GET_U32_BE( W[ 7], data, 28 ); + GET_U32_BE( W[ 8], data, 32 ); + GET_U32_BE( W[ 9], data, 36 ); + GET_U32_BE( W[10], data, 40 ); + GET_U32_BE( W[11], data, 44 ); + GET_U32_BE( W[12], data, 48 ); + GET_U32_BE( W[13], data, 52 ); + GET_U32_BE( W[14], data, 56 ); + GET_U32_BE( W[15], data, 60 ); #define SHR(x,n) ((x & 0xFFFFFFFF) >> n) #define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) @@ -241,7 +242,7 @@ static void sha2_process( sha2_context *ctx, const unsigned char data[64] ) static void sha2_update( sha2_context *ctx, const unsigned char *input, size_t ilen ) { size_t fill; - unsigned long left; + uint32_t left; if( ilen <= 0 ) return; @@ -249,10 +250,10 @@ static void sha2_update( sha2_context *ctx, const unsigned char *input, size_t i left = ctx->total[0] & 0x3F; fill = 64 - left; - ctx->total[0] += (unsigned long) ilen; + ctx->total[0] += (uint32_t) ilen; ctx->total[0] &= 0xFFFFFFFF; - if( ctx->total[0] < (unsigned long) ilen ) + if( ctx->total[0] < (uint32_t) ilen ) ctx->total[1]++; if( left && ilen >= fill ) @@ -292,16 +293,16 @@ static const unsigned char sha2_padding[64] = */ static void sha2_finish( sha2_context *ctx, unsigned char output[32] ) { - unsigned long last, padn; - unsigned long high, low; + uint32_t last, padn; + uint32_t high, low; unsigned char msglen[8]; high = ( ctx->total[0] >> 29 ) | ( ctx->total[1] << 3 ); low = ( ctx->total[0] << 3 ); - PUT_ULONG_BE( high, msglen, 0 ); - PUT_ULONG_BE( low, msglen, 4 ); + PUT_U32_BE( high, msglen, 0 ); + PUT_U32_BE( low, msglen, 4 ); last = ctx->total[0] & 0x3F; padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); @@ -309,16 +310,16 @@ static void sha2_finish( sha2_context *ctx, unsigned char output[32] ) sha2_update( ctx, (unsigned char *) sha2_padding, padn ); sha2_update( ctx, msglen, 8 ); - PUT_ULONG_BE( ctx->state[0], output, 0 ); - PUT_ULONG_BE( ctx->state[1], output, 4 ); - PUT_ULONG_BE( ctx->state[2], output, 8 ); - PUT_ULONG_BE( ctx->state[3], output, 12 ); - PUT_ULONG_BE( ctx->state[4], output, 16 ); - PUT_ULONG_BE( ctx->state[5], output, 20 ); - PUT_ULONG_BE( ctx->state[6], output, 24 ); + PUT_U32_BE( ctx->state[0], output, 0 ); + PUT_U32_BE( ctx->state[1], output, 4 ); + PUT_U32_BE( ctx->state[2], output, 8 ); + PUT_U32_BE( ctx->state[3], output, 12 ); + PUT_U32_BE( ctx->state[4], output, 16 ); + PUT_U32_BE( ctx->state[5], output, 20 ); + PUT_U32_BE( ctx->state[6], output, 24 ); if( ctx->is224 == 0 ) - PUT_ULONG_BE( ctx->state[7], output, 28 ); + PUT_U32_BE( ctx->state[7], output, 28 ); } /* diff --git a/lib/libalpm/signing.c b/lib/libalpm/signing.c index 7177d655..1e417164 100644 --- a/lib/libalpm/signing.c +++ b/lib/libalpm/signing.c @@ -17,8 +17,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -292,11 +290,34 @@ static int key_search(alpm_handle_t *handle, const char *fpr, pgpkey->email = key->uids->email; pgpkey->created = key->subkeys->timestamp; pgpkey->expires = key->subkeys->expires; - gpgme_release(ctx); - return 1; + pgpkey->length = key->subkeys->length; + pgpkey->revoked = key->subkeys->revoked; + + switch (key->subkeys->pubkey_algo) { + case GPGME_PK_RSA: + case GPGME_PK_RSA_E: + case GPGME_PK_RSA_S: + pgpkey->pubkey_algo = 'R'; + break; + + case GPGME_PK_DSA: + pgpkey->pubkey_algo = 'D'; + break; + + case GPGME_PK_ELG_E: + case GPGME_PK_ELG: + case GPGME_PK_ECDSA: + case GPGME_PK_ECDH: + pgpkey->pubkey_algo = 'E'; + break; + } + + ret = 1; error: - _alpm_log(handle, ALPM_LOG_DEBUG, "gpg error: %s\n", gpgme_strerror(err)); + if(ret != 1) { + _alpm_log(handle, ALPM_LOG_DEBUG, "gpg error: %s\n", gpgme_strerror(err)); + } free(full_fpr); gpgme_release(ctx); return ret; @@ -418,8 +439,13 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, if(!base64_sig) { sigpath = _alpm_sigpath(handle, path); - /* this will just help debugging */ - _alpm_access(handle, NULL, sigpath, R_OK); + if(_alpm_access(handle, NULL, sigpath, R_OK) != 0 + || (sigfile = fopen(sigpath, "rb")) == NULL) { + _alpm_log(handle, ALPM_LOG_DEBUG, "sig path %s could not be opened\n", + sigpath); + handle->pm_errno = ALPM_ERR_SIG_MISSING; + goto error; + } } /* does the file we are verifying exist? */ @@ -429,17 +455,6 @@ int _alpm_gpgme_checksig(alpm_handle_t *handle, const char *path, goto error; } - /* does the sig file exist (if we didn't get the data directly)? */ - if(!base64_sig) { - sigfile = fopen(sigpath, "rb"); - if(sigfile == NULL) { - _alpm_log(handle, ALPM_LOG_DEBUG, "sig path %s could not be opened\n", - sigpath); - handle->pm_errno = ALPM_ERR_SIG_MISSING; - goto error; - } - } - if(init_gpgme(handle)) { /* pm_errno was set in gpgme_init() */ goto error; diff --git a/lib/libalpm/signing.h b/lib/libalpm/signing.h index 315d6059..19ffef27 100644 --- a/lib/libalpm/signing.h +++ b/lib/libalpm/signing.h @@ -1,7 +1,7 @@ /* * signing.h * - * Copyright (c) 2008-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2008-2012 Pacman Development Team <pacman-dev@archlinux.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c index e500d90f..ca6b507e 100644 --- a/lib/libalpm/sync.c +++ b/lib/libalpm/sync.c @@ -1,7 +1,7 @@ /* * sync.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -21,8 +21,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <sys/types.h> /* off_t */ #include <stdlib.h> #include <stdio.h> @@ -251,7 +249,7 @@ alpm_list_t SYMEXPORT *alpm_find_group_pkgs(alpm_list_t *dbs, for(i = dbs; i; i = i->next) { alpm_db_t *db = i->data; - alpm_group_t *grp = alpm_db_readgroup(db, name); + alpm_group_t *grp = alpm_db_get_group(db, name); if(!grp) continue; @@ -291,7 +289,7 @@ static int compute_download_size(alpm_pkg_t *newpkg) alpm_handle_t *handle = newpkg->handle; int ret = 0; - if(newpkg->origin != PKG_FROM_SYNCDB) { + if(newpkg->origin != ALPM_PKG_FROM_SYNCDB) { newpkg->infolevel |= INFRQ_DSIZE; newpkg->download_size = 0; return 0; @@ -321,13 +319,13 @@ static int compute_download_size(alpm_pkg_t *newpkg) /* tell the caller that we have a partial */ ret = 1; - } else if(handle->usedelta) { + } else if(handle->deltaratio > 0.0) { off_t dltsize; dltsize = _alpm_shortest_delta_path(handle, newpkg->deltas, newpkg->filename, &newpkg->delta_path); - if(newpkg->delta_path && (dltsize < newpkg->size * MAX_DELTA_RATIO)) { + if(newpkg->delta_path && (dltsize < newpkg->size * handle->deltaratio)) { _alpm_log(handle, ALPM_LOG_DEBUG, "using delta size\n"); size = dltsize; } else { @@ -368,7 +366,7 @@ int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data) for(i = trans->add; i; i = i->next) { alpm_pkg_t *spkg = i->data; - from_sync += (spkg->origin == PKG_FROM_SYNCDB); + from_sync += (spkg->origin == ALPM_PKG_FROM_SYNCDB); } /* ensure all sync database are valid if we will be using them */ @@ -424,7 +422,7 @@ int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data) see if they'd like to ignore them rather than failing the sync */ if(unresolvable != NULL) { int remove_unresolvable = 0; - enum _alpm_errno_t saved_err = handle->pm_errno; + alpm_errno_t saved_err = handle->pm_errno; QUESTION(handle, ALPM_QUESTION_REMOVE_PKGS, unresolvable, NULL, NULL, &remove_unresolvable); if(remove_unresolvable) { @@ -696,11 +694,11 @@ static int apply_deltas(alpm_handle_t *handle) } else { /* len = cachedir len + from len + '/' + null */ len = strlen(cachedir) + strlen(d->from) + 2; - CALLOC(from, len, sizeof(char), RET_ERR(handle, ALPM_ERR_MEMORY, 1)); + MALLOC(from, len, RET_ERR(handle, ALPM_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(handle, ALPM_ERR_MEMORY, 1)); + MALLOC(to, len, RET_ERR(handle, ALPM_ERR_MEMORY, 1)); snprintf(to, len, "%s/%s", cachedir, d->to); /* build the patch command */ @@ -758,7 +756,7 @@ static int apply_deltas(alpm_handle_t *handle) * @return 1 if file was removed, 0 otherwise */ static int prompt_to_delete(alpm_handle_t *handle, const char *filepath, - enum _alpm_errno_t reason) + alpm_errno_t reason) { int doremove = 0; QUESTION(handle, ALPM_QUESTION_CORRUPTED_PKG, (char *)filepath, @@ -783,7 +781,7 @@ static int validate_deltas(alpm_handle_t *handle, alpm_list_t *deltas) alpm_delta_t *d = i->data; char *filepath = _alpm_filecache_find(handle, d->delta); - if(_alpm_test_checksum(filepath, d->delta_md5, ALPM_CSUM_MD5)) { + if(_alpm_test_checksum(filepath, d->delta_md5, ALPM_PKG_VALIDATION_MD5SUM)) { errors = alpm_list_add(errors, filepath); } else { FREE(filepath); @@ -804,11 +802,96 @@ static int validate_deltas(alpm_handle_t *handle, alpm_list_t *deltas) return 0; } +static struct dload_payload *build_payload(alpm_handle_t *handle, + const char *filename, size_t size, alpm_list_t *servers) +{ + struct dload_payload *payload; + + CALLOC(payload, 1, sizeof(*payload), RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); + STRDUP(payload->remote_name, filename, RET_ERR(handle, ALPM_ERR_MEMORY, NULL)); + payload->max_size = size; + payload->servers = servers; + return payload; +} + +static int find_dl_candidates(alpm_db_t *repo, alpm_list_t **files, alpm_list_t **deltas) +{ + alpm_list_t *i; + alpm_handle_t *handle = repo->handle; + + for(i = handle->trans->add; i; i = i->next) { + alpm_pkg_t *spkg = i->data; + + if(spkg->origin != ALPM_PKG_FROM_FILE && repo == spkg->origin_data.db) { + alpm_list_t *delta_path = spkg->delta_path; + + if(!repo->servers) { + handle->pm_errno = ALPM_ERR_SERVER_NONE; + _alpm_log(handle, ALPM_LOG_ERROR, "%s: %s\n", + alpm_strerror(handle->pm_errno), repo->treename); + return 1; + } + + if(delta_path) { + /* using deltas */ + alpm_list_t *dlts; + for(dlts = delta_path; dlts; dlts = dlts->next) { + alpm_delta_t *delta = dlts->data; + if(delta->download_size != 0) { + struct dload_payload *payload = build_payload( + handle, delta->delta, delta->delta_size, repo->servers); + ASSERT(payload, return -1); + *files = alpm_list_add(*files, payload); + } + /* keep a list of all the delta files for md5sums */ + *deltas = alpm_list_add(*deltas, delta); + } + + } else if(spkg->download_size != 0) { + struct dload_payload *payload; + ASSERT(spkg->filename != NULL, RET_ERR(handle, ALPM_ERR_PKG_INVALID_NAME, -1)); + payload = build_payload(handle, spkg->filename, spkg->size, repo->servers); + ASSERT(payload, return -1); + *files = alpm_list_add(*files, payload); + } + } + } + + return 0; +} + +static int download_single_file(alpm_handle_t *handle, struct dload_payload *payload, + const char *cachedir) +{ + const alpm_list_t *server; + + payload->handle = handle; + payload->allow_resume = 1; + + for(server = payload->servers; server; server = server->next) { + const char *server_url = server->data; + size_t len; + + /* print server + filename into a buffer */ + len = strlen(server_url) + strlen(payload->remote_name) + 2; + MALLOC(payload->fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); + snprintf(payload->fileurl, len, "%s/%s", server_url, payload->remote_name); + + if(_alpm_download(payload, cachedir, NULL) != -1) { + return 0; + } + + FREE(payload->fileurl); + payload->unlink_on_fail = 0; + } + + return -1; +} + static int download_files(alpm_handle_t *handle, alpm_list_t **deltas) { const char *cachedir; - alpm_list_t *i, *j; - alpm_list_t *files = NULL; + alpm_list_t *i, *files = NULL; int errors = 0; cachedir = _alpm_filecache_setup(handle); @@ -827,93 +910,53 @@ static int download_files(alpm_handle_t *handle, alpm_list_t **deltas) handle->totaldlcb(total_size); } - /* group sync records by repository and download */ for(i = handle->dbs_sync; i; i = i->next) { - alpm_db_t *current = i->data; - - for(j = handle->trans->add; j; j = j->next) { - alpm_pkg_t *spkg = j->data; - - if(spkg->origin != PKG_FROM_FILE && current == spkg->origin_data.db) { - alpm_list_t *delta_path = spkg->delta_path; - if(delta_path) { - /* using deltas */ - alpm_list_t *dlts; - for(dlts = delta_path; dlts; dlts = dlts->next) { - alpm_delta_t *delta = dlts->data; - if(delta->download_size != 0) { - struct dload_payload *dpayload; - - CALLOC(dpayload, 1, sizeof(*dpayload), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); - STRDUP(dpayload->remote_name, delta->delta, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); - dpayload->max_size = delta->delta_size; - - files = alpm_list_add(files, dpayload); - } - /* keep a list of all the delta files for md5sums */ - *deltas = alpm_list_add(*deltas, delta); - } + errors += find_dl_candidates(i->data, &files, deltas); + } - } else if(spkg->download_size != 0) { - struct dload_payload *payload; + if(files) { + /* check for necessary disk space for download */ + if(handle->checkspace) { + off_t *file_sizes; + size_t idx, num_files; + int ret; - ASSERT(spkg->filename != NULL, RET_ERR(handle, ALPM_ERR_PKG_INVALID_NAME, -1)); - CALLOC(payload, 1, sizeof(*payload), RET_ERR(handle, ALPM_ERR_MEMORY, -1)); - STRDUP(payload->remote_name, spkg->filename, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); - payload->max_size = spkg->size; + _alpm_log(handle, ALPM_LOG_DEBUG, "checking available disk space for download\n"); - files = alpm_list_add(files, payload); - } + num_files = alpm_list_count(files); + CALLOC(file_sizes, num_files, sizeof(off_t), goto finish); + for(i = files, idx = 0; i; i = i->next, idx++) { + const struct dload_payload *payload = i->data; + file_sizes[idx] = payload->max_size; } - } - if(files) { - if(!current->servers) { - handle->pm_errno = ALPM_ERR_SERVER_NONE; - _alpm_log(handle, ALPM_LOG_ERROR, "%s: %s\n", - alpm_strerror(handle->pm_errno), current->treename); + ret = _alpm_check_downloadspace(handle, cachedir, num_files, file_sizes); + free(file_sizes); + + if(ret != 0) { errors++; - continue; + goto finish; } + } - EVENT(handle, ALPM_EVENT_RETRIEVE_START, current->treename, NULL); - for(j = files; j; j = j->next) { - struct dload_payload *payload = j->data; - alpm_list_t *server; - int ret = -1; - for(server = current->servers; server; server = server->next) { - const char *server_url = server->data; - size_t len; - - /* print server + filename into a buffer */ - len = strlen(server_url) + strlen(payload->remote_name) + 2; - MALLOC(payload->fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); - snprintf(payload->fileurl, len, "%s/%s", server_url, payload->remote_name); - payload->handle = handle; - payload->allow_resume = 1; - - ret = _alpm_download(payload, cachedir, NULL); - if(ret != -1) { - break; - } - FREE(payload->fileurl); - payload->unlink_on_fail = 0; - } - if(ret == -1) { - errors++; - _alpm_log(handle, ALPM_LOG_WARNING, _("failed to retrieve some files from %s\n"), - current->treename); - } + EVENT(handle, ALPM_EVENT_RETRIEVE_START, NULL, NULL); + for(i = files; i; i = i->next) { + if(download_single_file(handle, i->data, cachedir) == -1) { + errors++; + _alpm_log(handle, ALPM_LOG_WARNING, _("failed to retrieve some files\n")); } - - alpm_list_free_inner(files, (alpm_list_fn_free)_alpm_dload_payload_reset); - FREELIST(files); } } - for(j = handle->trans->add; j; j = j->next) { - alpm_pkg_t *pkg = j->data; +finish: + if(files) { + alpm_list_free_inner(files, (alpm_list_fn_free)_alpm_dload_payload_reset); + FREELIST(files); + } + + for(i = handle->trans->add; i; i = i->next) { + alpm_pkg_t *pkg = i->data; pkg->infolevel &= ~INFRQ_DSIZE; pkg->download_size = 0; } @@ -934,7 +977,8 @@ static int check_validity(alpm_handle_t *handle, char *path; alpm_siglist_t *siglist; alpm_siglevel_t level; - enum _alpm_errno_t error; + alpm_pkgvalidation_t validation; + alpm_errno_t error; }; size_t current = 0, current_bytes = 0; alpm_list_t *i, *errors = NULL; @@ -943,12 +987,12 @@ static int check_validity(alpm_handle_t *handle, EVENT(handle, ALPM_EVENT_INTEGRITY_START, NULL, NULL); for(i = handle->trans->add; i; i = i->next, current++) { - struct validity v = { i->data, NULL, NULL, 0, 0 }; + struct validity v = { i->data, NULL, NULL, 0, 0, 0 }; int percent = (int)(((double)current_bytes / total_bytes) * 100); PROGRESS(handle, ALPM_PROGRESS_INTEGRITY_START, "", percent, total, current); - if(v.pkg->origin == PKG_FROM_FILE) { + if(v.pkg->origin == ALPM_PKG_FROM_FILE) { continue; /* pkg_load() has been already called, this package is valid */ } @@ -957,7 +1001,7 @@ static int check_validity(alpm_handle_t *handle, v.level = alpm_db_get_siglevel(alpm_pkg_get_db(v.pkg)); if(_alpm_pkg_validate_internal(handle, v.path, v.pkg, - v.level, &v.siglist) == -1) { + v.level, &v.siglist, &v.validation) == -1) { v.error = handle->pm_errno; struct validity *invalid = malloc(sizeof(struct validity)); memcpy(invalid, &v, sizeof(struct validity)); @@ -966,6 +1010,7 @@ static int check_validity(alpm_handle_t *handle, alpm_siglist_cleanup(v.siglist); free(v.siglist); free(v.path); + v.pkg->validation = v.validation; } } @@ -1023,7 +1068,7 @@ static int load_packages(alpm_handle_t *handle, alpm_list_t **data, PROGRESS(handle, ALPM_PROGRESS_LOAD_START, "", percent, total, current); - if(spkg->origin == PKG_FROM_FILE) { + if(spkg->origin == ALPM_PKG_FROM_FILE) { continue; /* pkg_load() has been already called, this package is valid */ } @@ -1045,6 +1090,8 @@ static int load_packages(alpm_handle_t *handle, alpm_list_t **data, free(filepath); /* copy over the install reason */ pkgfile->reason = spkg->reason; + /* copy over validation method */ + pkgfile->validation = spkg->validation; i->data = pkgfile; /* spkg has been removed from the target list, so we can free the * sync-specific fields */ @@ -1091,7 +1138,7 @@ int _alpm_sync_commit(alpm_handle_t *handle, alpm_list_t **data) * realistically if there are small and huge packages involved */ for(i = trans->add; i; i = i->next) { alpm_pkg_t *spkg = i->data; - if(spkg->origin != PKG_FROM_FILE) { + if(spkg->origin != ALPM_PKG_FROM_FILE) { total_bytes += spkg->size; } total++; @@ -1120,7 +1167,7 @@ int _alpm_sync_commit(alpm_handle_t *handle, alpm_list_t **data) trans->state = STATE_COMMITING; /* fileconflict check */ - if(!(trans->flags & ALPM_TRANS_FLAG_FORCE)) { + if(!(trans->flags & (ALPM_TRANS_FLAG_FORCE|ALPM_TRANS_FLAG_DBONLY))) { EVENT(handle, ALPM_EVENT_FILECONFLICTS_START, NULL, NULL); _alpm_log(handle, ALPM_LOG_DEBUG, "looking for file conflicts\n"); @@ -1145,7 +1192,7 @@ int _alpm_sync_commit(alpm_handle_t *handle, alpm_list_t **data) _alpm_log(handle, ALPM_LOG_DEBUG, "checking available disk space\n"); if(_alpm_check_diskspace(handle) == -1) { - _alpm_log(handle, ALPM_LOG_ERROR, "%s\n", _("not enough free disk space")); + _alpm_log(handle, ALPM_LOG_ERROR, _("not enough free disk space\n")); return -1; } diff --git a/lib/libalpm/sync.h b/lib/libalpm/sync.h index 472d1dfc..496f5258 100644 --- a/lib/libalpm/sync.h +++ b/lib/libalpm/sync.h @@ -1,7 +1,7 @@ /* * sync.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org> diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c index cb97a4aa..08f70dd7 100644 --- a/lib/libalpm/trans.c +++ b/lib/libalpm/trans.c @@ -1,7 +1,7 @@ /* * trans.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -21,8 +21,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -278,8 +276,8 @@ static int grep(const char *fn, const char *needle) int _alpm_runscriptlet(alpm_handle_t *handle, const char *filepath, const char *script, const char *ver, const char *oldver, int is_archive) { - char cmdline[PATH_MAX]; - char *argv[] = { "sh", "-c", cmdline, NULL }; + char arg0[64], arg1[3], cmdline[PATH_MAX]; + char *argv[] = { arg0, arg1, cmdline, NULL }; char *tmpdir, *scriptfn = NULL, *scriptpath; int retval = 0; size_t len; @@ -295,6 +293,9 @@ int _alpm_runscriptlet(alpm_handle_t *handle, const char *filepath, return 0; } + strcpy(arg0, SCRIPTLET_SHELL); + strcpy(arg1, "-c"); + /* create a directory in $root/tmp/ for copying/extracting the scriptlet */ len = strlen(handle->root) + strlen("tmp/alpm_XXXXXX") + 1; MALLOC(tmpdir, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); @@ -345,7 +346,7 @@ int _alpm_runscriptlet(alpm_handle_t *handle, const char *filepath, _alpm_log(handle, ALPM_LOG_DEBUG, "executing \"%s\"\n", cmdline); - retval = _alpm_run_chroot(handle, "/bin/sh", argv); + retval = _alpm_run_chroot(handle, SCRIPTLET_SHELL, argv); cleanup: if(scriptfn && unlink(scriptfn)) { diff --git a/lib/libalpm/trans.h b/lib/libalpm/trans.h index ff944b09..acde9219 100644 --- a/lib/libalpm/trans.h +++ b/lib/libalpm/trans.h @@ -1,7 +1,7 @@ /* * trans.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index 0e5e8a00..033058a0 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -22,24 +22,17 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - -#include <stdio.h> #include <stdlib.h> -#include <stdarg.h> -#include <string.h> #include <unistd.h> #include <ctype.h> #include <dirent.h> -#include <fcntl.h> #include <time.h> #include <syslog.h> #include <errno.h> #include <limits.h> -#include <sys/types.h> -#include <sys/stat.h> #include <sys/wait.h> #include <locale.h> /* setlocale */ +#include <fnmatch.h> /* libarchive */ #include <archive.h> @@ -62,11 +55,19 @@ #include "trans.h" #ifndef HAVE_STRSEP -/* This is a replacement for strsep which is not portable (missing on Solaris). - * Copyright (c) 2001 by François Gouget <fgouget_at_codeweavers.com> */ -char* strsep(char** str, const char* delims) +/** Extracts tokens from a string. + * Replaces strset which is not portable (missing on Solaris). + * Copyright (c) 2001 by François Gouget <fgouget_at_codeweavers.com> + * Modifies str to point to the first character after the token if one is + * found, or NULL if one is not. + * @param str string containing delimited tokens to parse + * @param delim character delimiting tokens in str + * @return pointer to the first token in str if str is not NULL, NULL if + * str is NULL + */ +char *strsep(char **str, const char *delims) { - char* token; + char *token; if(*str==NULL) { /* No more tokens */ @@ -93,138 +94,118 @@ int _alpm_makepath(const char *path) return _alpm_makepath_mode(path, 0755); } -/* does the same thing as 'mkdir -p' */ +/** Creates a directory, including parents if needed, similar to 'mkdir -p'. + * @param path directory path to create + * @param mode permission mode for created directories + * @return 0 on success, 1 on error + */ int _alpm_makepath_mode(const char *path, mode_t mode) { - /* 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); + char *ptr, *str; + mode_t oldmask; int ret = 0; - orig = strdup(path); - incr = calloc(strlen(orig) + 1, sizeof(char)); - str = orig; - while((ptr = strsep(&str, "/"))) { - if(strlen(ptr)) { - /* 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(access(incr, F_OK)) { - if(mkdir(incr, mode)) { - ret = 1; - break; - } - } - } - } - free(orig); - free(incr); - umask(oldmask); - return ret; -} + STRDUP(str, path, return 1); -int _alpm_copyfile(const char *src, const char *dest) -{ - FILE *in, *out; - size_t len; - char *buf; - int ret = 0; + oldmask = umask(0000); - in = fopen(src, "rb"); - if(in == NULL) { - return 1; - } - out = fopen(dest, "wb"); - if(out == NULL) { - fclose(in); - return 1; - } + for(ptr = str; *ptr; ptr++) { + /* detect mid-path condition and zero length paths */ + if(*ptr != '/' || ptr == str || ptr[-1] == '/') { + continue; + } - MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, ret = 1; goto cleanup); + /* temporarily mask the end of the path */ + *ptr = '\0'; - /* do the actual file copy */ - while((len = fread(buf, 1, ALPM_BUFFER_SIZE, in))) { - size_t nwritten = 0; - nwritten = fwrite(buf, 1, len, out); - if((nwritten != len) || ferror(out)) { - ret = -1; - goto cleanup; + if(mkdir(str, mode) < 0 && errno != EEXIST) { + ret = 1; + goto done; } + + /* restore path separator */ + *ptr = '/'; } - /* chmod dest to permissions of src, as long as it is not a symlink */ - struct stat statbuf; - if(!stat(src, &statbuf)) { - if(! S_ISLNK(statbuf.st_mode)) { - fchmod(fileno(out), statbuf.st_mode); - } - } else { - /* stat was unsuccessful */ + /* end of the string. add the full path. It will already exist when the path + * passed in has a trailing slash. */ + if(mkdir(str, mode) < 0 && errno != EEXIST) { ret = 1; } -cleanup: - fclose(in); - fclose(out); - free(buf); +done: + umask(oldmask); + free(str); return ret; } -/* Trim whitespace and newlines from a string -*/ -char *_alpm_strtrim(char *str) +/** Copies a file. + * @param src file path to copy from + * @param dest file path to copy to + * @return 0 on success, 1 on error + */ +int _alpm_copyfile(const char *src, const char *dest) { - char *pch = str; + char *buf; + int in, out, ret = 1; + ssize_t nread; + struct stat st; - if(*str == '\0') { - /* string is empty, so we're done. */ - return str; + MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, return 1); + + OPEN(in, src, O_RDONLY); + do { + out = open(dest, O_WRONLY | O_CREAT, 0000); + } while(out == -1 && errno == EINTR); + if(in < 0 || out < 0) { + goto cleanup; } - while(isspace((unsigned char)*pch)) { - pch++; + if(fstat(in, &st) || fchmod(out, st.st_mode)) { + goto cleanup; } - if(pch != str) { - size_t len = strlen(pch); - if(len) { - memmove(str, pch, len + 1); - } else { - *str = '\0'; + + /* do the actual file copy */ + while((nread = read(in, buf, ALPM_BUFFER_SIZE)) > 0 || errno == EINTR) { + ssize_t nwrite = 0; + if(nread < 0) { + continue; } + do { + nwrite = write(out, buf + nwrite, nread); + if(nwrite >= 0) { + nread -= nwrite; + } else if(errno != EINTR) { + goto cleanup; + } + } while(nread > 0); } + ret = 0; - /* check if there wasn't anything but whitespace in the string. */ - if(*str == '\0') { - return str; +cleanup: + free(buf); + if(in >= 0) { + CLOSE(in); } - - pch = (str + (strlen(str) - 1)); - while(isspace((unsigned char)*pch)) { - pch--; + if(out >= 0) { + CLOSE(out); } - *++pch = '\0'; - - return str; + return ret; } -/** - * Trim trailing newline from a string (if one exists). +/** Trim trailing newlines from a string (if any exist). * @param str a single line of text + * @param len size of str, if known, else 0 * @return the length of the trimmed string */ -size_t _alpm_strip_newline(char *str) +size_t _alpm_strip_newline(char *str, size_t len) { - size_t len; if(*str == '\0') { return 0; } - len = strlen(str); + if(len == 0) { + len = strlen(str); + } while(len > 0 && str[len - 1] == '\n') { len--; } @@ -235,9 +216,70 @@ size_t _alpm_strip_newline(char *str) /* Compression functions */ -/** - * @brief Unpack a specific file in an archive. - * +/** Open an archive for reading and perform the necessary boilerplate. + * This takes care of creating the libarchive 'archive' struct, setting up + * compression and format options, opening a file descriptor, setting up the + * buffer size, and performing a stat on the path once opened. + * On error, no file descriptor is opened, and the archive pointer returned + * will be set to NULL. + * @param handle the context handle + * @param path the path of the archive to open + * @param buf space for a stat buffer for the given path + * @param archive pointer to place the created archive object + * @param error error code to set on failure to open archive + * @return -1 on failure, >=0 file descriptor on success + */ +int _alpm_open_archive(alpm_handle_t *handle, const char *path, + struct stat *buf, struct archive **archive, alpm_errno_t error) +{ + int fd; + size_t bufsize = ALPM_BUFFER_SIZE; + errno = 0; + + if((*archive = archive_read_new()) == NULL) { + RET_ERR(handle, ALPM_ERR_LIBARCHIVE, -1); + } + + archive_read_support_compression_all(*archive); + archive_read_support_format_all(*archive); + + _alpm_log(handle, ALPM_LOG_DEBUG, "opening archive %s\n", path); + OPEN(fd, path, O_RDONLY); + if(fd < 0) { + _alpm_log(handle, ALPM_LOG_ERROR, + _("could not open file %s: %s\n"), path, strerror(errno)); + goto error; + } + + if(fstat(fd, buf) != 0) { + _alpm_log(handle, ALPM_LOG_ERROR, + _("could not stat file %s: %s\n"), path, strerror(errno)); + goto error; + } +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + if(buf->st_blksize > ALPM_BUFFER_SIZE) { + bufsize = buf->st_blksize; + } +#endif + + if(archive_read_open_fd(*archive, fd, bufsize) != ARCHIVE_OK) { + _alpm_log(handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), + path, archive_error_string(*archive)); + goto error; + } + + return fd; + +error: + archive_read_finish(*archive); + *archive = NULL; + if(fd >= 0) { + CLOSE(fd); + } + RET_ERR(handle, error, -1); +} + +/** Unpack a specific file in an archive. * @param handle the context handle * @param archive the archive to unpack * @param prefix where to extract the files @@ -258,46 +300,33 @@ int _alpm_unpack_single(alpm_handle_t *handle, const char *archive, return ret; } -/** - * @brief Unpack a list of files in an archive. - * +/** Unpack a list of files in an archive. * @param handle the context handle - * @param archive the archive to unpack + * @param path the archive to unpack * @param prefix where to extract the files * @param list a list of files within the archive to unpack or NULL for all * @param breakfirst break after the first entry found - * * @return 0 on success, 1 on failure */ -int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix, +int _alpm_unpack(alpm_handle_t *handle, const char *path, const char *prefix, alpm_list_t *list, int breakfirst) { int ret = 0; mode_t oldmask; - struct archive *_archive; + struct archive *archive; struct archive_entry *entry; - int cwdfd; - - if((_archive = archive_read_new()) == NULL) { - RET_ERR(handle, ALPM_ERR_LIBARCHIVE, 1); - } - - archive_read_support_compression_all(_archive); - archive_read_support_format_all(_archive); + struct stat buf; + int fd, cwdfd; - if(archive_read_open_filename(_archive, archive, - ALPM_BUFFER_SIZE) != ARCHIVE_OK) { - _alpm_log(handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), archive, - archive_error_string(_archive)); - RET_ERR(handle, ALPM_ERR_PKG_OPEN, 1); + fd = _alpm_open_archive(handle, path, &buf, &archive, ALPM_ERR_PKG_OPEN); + if(fd < 0) { + return 1; } oldmask = umask(0022); /* save the cwd so we can restore it later */ - do { - cwdfd = open(".", O_RDONLY); - } while(cwdfd == -1 && errno == EINTR); + OPEN(cwdfd, ".", O_RDONLY); if(cwdfd < 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n")); } @@ -310,19 +339,12 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix, goto cleanup; } - while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) { - const struct stat *st; - const char *entryname; /* the name of the file in the archive */ + while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) { + const char *entryname; + mode_t mode; - st = archive_entry_stat(entry); entryname = archive_entry_pathname(entry); - if(S_ISREG(st->st_mode)) { - archive_entry_set_perm(entry, 0644); - } else if(S_ISDIR(st->st_mode)) { - archive_entry_set_perm(entry, 0755); - } - /* If specific files were requested, skip entries that don't match. */ if(list) { char *entry_prefix = strdup(entryname); @@ -333,7 +355,7 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix, char *found = alpm_list_find_str(list, entry_prefix); free(entry_prefix); if(!found) { - if(archive_read_data_skip(_archive) != ARCHIVE_OK) { + if(archive_read_data_skip(archive) != ARCHIVE_OK) { ret = 1; goto cleanup; } @@ -343,15 +365,22 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix, } } + mode = archive_entry_mode(entry); + if(S_ISREG(mode)) { + archive_entry_set_perm(entry, 0644); + } else if(S_ISDIR(mode)) { + archive_entry_set_perm(entry, 0755); + } + /* Extract the archive entry. */ - int readret = archive_read_extract(_archive, entry, 0); + int readret = archive_read_extract(archive, entry, 0); if(readret == ARCHIVE_WARN) { /* operation succeeded but a non-critical error was encountered */ _alpm_log(handle, ALPM_LOG_WARNING, _("warning given when extracting %s (%s)\n"), - entryname, archive_error_string(_archive)); + entryname, archive_error_string(archive)); } else if(readret != ARCHIVE_OK) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not extract %s (%s)\n"), - entryname, archive_error_string(_archive)); + entryname, archive_error_string(archive)); ret = 1; goto cleanup; } @@ -363,63 +392,20 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix, cleanup: umask(oldmask); - archive_read_finish(_archive); + archive_read_finish(archive); + CLOSE(fd); if(cwdfd >= 0) { if(fchdir(cwdfd) != 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not restore working directory (%s)\n"), strerror(errno)); } - close(cwdfd); + CLOSE(cwdfd); } return ret; } -/* does the same thing as 'rm -rf' */ -int _alpm_rmrf(const char *path) -{ - int errflag = 0; - struct dirent *dp; - DIR *dirp; - struct stat st; - - if(_alpm_lstat(path, &st) == 0) { - if(!S_ISDIR(st.st_mode)) { - if(!unlink(path)) { - return 0; - } else { - if(errno == ENOENT) { - return 0; - } else { - return 1; - } - } - } else { - dirp = opendir(path); - if(!dirp) { - return 1; - } - for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { - if(dp->d_name) { - if(strcmp(dp->d_name, "..") != 0 && strcmp(dp->d_name, ".") != 0) { - char name[PATH_MAX]; - sprintf(name, "%s/%s", path, dp->d_name); - errflag += _alpm_rmrf(name); - } - } - } - closedir(dirp); - if(rmdir(path)) { - errflag++; - } - } - return errflag; - } - return 0; -} - -/** - * Determine if there are files in a directory +/** Determine if there are files in a directory. * @param handle the context handle * @param path the full absolute directory path * @param full_count whether to return an exact count of files @@ -460,6 +446,13 @@ ssize_t _alpm_files_in_directory(alpm_handle_t *handle, const char *path, return files; } +/** Write formatted message to log. + * @param handle the context handle + * @param format formatted string to write out + * @param args formatting arguments + * @return 0 or number of characters written on success, vfprintf return value + * on error + */ int _alpm_logaction(alpm_handle_t *handle, const char *fmt, va_list args) { int ret = 0; @@ -491,16 +484,20 @@ int _alpm_logaction(alpm_handle_t *handle, const char *fmt, va_list args) return ret; } -int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[]) +/** Execute a command with arguments in a chroot. + * @param handle the context handle + * @param cmd command to execute + * @param argv arguments to pass to cmd + * @return 0 on success, 1 on error + */ +int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[]) { pid_t pid; int pipefd[2], cwdfd; int retval = 0; /* save the cwd so we can restore it later */ - do { - cwdfd = open(".", O_RDONLY); - } while(cwdfd == -1 && errno == EINTR); + OPEN(cwdfd, ".", O_RDONLY); if(cwdfd < 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n")); } @@ -513,7 +510,7 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[] } _alpm_log(handle, ALPM_LOG_DEBUG, "executing \"%s\" under chroot \"%s\"\n", - path, handle->root); + cmd, handle->root); /* Flush open fds before fork() to avoid cloning buffers */ fflush(NULL); @@ -534,12 +531,12 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[] if(pid == 0) { /* this code runs for the child only (the actual chroot/exec) */ - close(1); - close(2); + CLOSE(1); + CLOSE(2); while(dup2(pipefd[1], 1) == -1 && errno == EINTR); while(dup2(pipefd[1], 2) == -1 && errno == EINTR); - close(pipefd[0]); - close(pipefd[1]); + CLOSE(pipefd[0]); + CLOSE(pipefd[1]); /* use fprintf instead of _alpm_log to send output through the parent */ if(chroot(handle->root) != 0) { @@ -552,7 +549,8 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[] exit(1); } umask(0022); - execv(path, argv); + execv(cmd, argv); + /* execv only returns if there was an error */ fprintf(stderr, _("call to execv failed (%s)\n"), strerror(errno)); exit(1); } else { @@ -560,10 +558,10 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[] int status; FILE *pipe_file; - close(pipefd[1]); + CLOSE(pipefd[1]); pipe_file = fdopen(pipefd[0], "r"); if(pipe_file == NULL) { - close(pipefd[0]); + CLOSE(pipefd[0]); retval = 1; } else { while(!feof(pipe_file)) { @@ -605,12 +603,16 @@ cleanup: _alpm_log(handle, ALPM_LOG_ERROR, _("could not restore working directory (%s)\n"), strerror(errno)); } - close(cwdfd); + CLOSE(cwdfd); } return retval; } +/** Run ldconfig in a chroot. + * @param handle the context handle + * @return 0 on success, 1 on error + */ int _alpm_ldconfig(alpm_handle_t *handle) { char line[PATH_MAX]; @@ -621,7 +623,9 @@ int _alpm_ldconfig(alpm_handle_t *handle) if(access(line, F_OK) == 0) { snprintf(line, PATH_MAX, "%ssbin/ldconfig", handle->root); if(access(line, X_OK) == 0) { - char *argv[] = { "ldconfig", NULL }; + char arg0[32]; + char *argv[] = { arg0, NULL }; + strcpy(arg0, "ldconfig"); return _alpm_run_chroot(handle, "/sbin/ldconfig", argv); } } @@ -629,8 +633,13 @@ int _alpm_ldconfig(alpm_handle_t *handle) return 0; } -/* Helper function for comparing strings using the - * alpm "compare func" signature */ +/** Helper function for comparing strings using the alpm "compare func" + * signature. + * @param s1 first string to be compared + * @param s2 second string to be compared + * @return 0 if strings are equal, positive int if first unequal character + * has a greater value in s1, negative if it has a greater value in s2 + */ int _alpm_str_cmp(const void *s1, const void *s2) { return strcmp(s1, s2); @@ -671,7 +680,8 @@ const char *_alpm_filecache_setup(alpm_handle_t *handle) { struct stat buf; alpm_list_t *i; - char *cachedir, *tmpdir; + char *cachedir; + const char *tmpdir; /* Loop through the cache dirs until we find a usable directory */ for(i = handle->cachedirs; i; i = i->next) { @@ -687,7 +697,7 @@ const char *_alpm_filecache_setup(alpm_handle_t *handle) } else if(!S_ISDIR(buf.st_mode)) { _alpm_log(handle, ALPM_LOG_DEBUG, "skipping cachedir, not a directory: %s\n", cachedir); - } else if(access(cachedir, W_OK) != 0) { + } else if(_alpm_access(handle, NULL, cachedir, W_OK) != 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "skipping cachedir, not writable: %s\n", cachedir); } else if(!(buf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) { @@ -739,51 +749,64 @@ int _alpm_lstat(const char *path, struct stat *buf) } #ifdef HAVE_LIBSSL +/** Compute the MD5 message digest of a file. + * @param path file path of file to compute MD5 digest of + * @param output string to hold computed MD5 digest + * @return 0 on success, 1 on file open error, 2 on file read error + */ static int md5_file(const char *path, unsigned char output[16]) { - FILE *f; - size_t n; MD5_CTX ctx; unsigned char *buf; + ssize_t n; + int fd; - CALLOC(buf, ALPM_BUFFER_SIZE, sizeof(unsigned char), return 1); + MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, return 1); - if((f = fopen(path, "rb")) == NULL) { + OPEN(fd, path, O_RDONLY); + if(fd < 0) { free(buf); return 1; } MD5_Init(&ctx); - while((n = fread(buf, 1, ALPM_BUFFER_SIZE, f)) > 0) { + while((n = read(fd, buf, ALPM_BUFFER_SIZE)) > 0 || errno == EINTR) { + if(n < 0) { + continue; + } MD5_Update(&ctx, buf, n); } - MD5_Final(output, &ctx); - - memset(&ctx, 0, sizeof(MD5_CTX)); + CLOSE(fd); free(buf); - if(ferror(f) != 0) { - fclose(f); + if(n < 0) { return 2; } - fclose(f); + MD5_Final(output, &ctx); return 0; } /* third param is so we match the PolarSSL definition */ +/** Compute the SHA-224 or SHA-256 message digest of a file. + * @param path file path of file to compute SHA2 digest of + * @param output string to hold computed SHA2 digest + * @param is224 use SHA-224 instead of SHA-256 + * @return 0 on success, 1 on file open error, 2 on file read error + */ static int sha2_file(const char *path, unsigned char output[32], int is224) { - FILE *f; - size_t n; SHA256_CTX ctx; unsigned char *buf; + ssize_t n; + int fd; - CALLOC(buf, ALPM_BUFFER_SIZE, sizeof(unsigned char), return 1); + MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, return 1); - if((f = fopen(path, "rb")) == NULL) { + OPEN(fd, path, O_RDONLY); + if(fd < 0) { free(buf); return 1; } @@ -794,7 +817,10 @@ static int sha2_file(const char *path, unsigned char output[32], int is224) SHA256_Init(&ctx); } - while((n = fread(buf, 1, ALPM_BUFFER_SIZE, f)) > 0) { + while((n = read(fd, buf, ALPM_BUFFER_SIZE)) > 0 || errno == EINTR) { + if(n < 0) { + continue; + } if(is224) { SHA224_Update(&ctx, buf, n); } else { @@ -802,24 +828,45 @@ static int sha2_file(const char *path, unsigned char output[32], int is224) } } + CLOSE(fd); + free(buf); + + if(n < 0) { + return 2; + } + if(is224) { SHA224_Final(output, &ctx); } else { SHA256_Final(output, &ctx); } + return 0; +} +#endif - memset(&ctx, 0, sizeof(SHA256_CTX)); - free(buf); +/** Create a string representing bytes in hexadecimal. + * @param bytes the bytes to represent in hexadecimal + * @param size number of bytes to consider + * @return a NULL terminated string with the hexadecimal representation of + * bytes or NULL on error. This string must be freed. + */ +static char *hex_representation(unsigned char *bytes, size_t size) +{ + static const char *hex_digits = "0123456789abcdef"; + char *str; + size_t i; - if(ferror(f) != 0) { - fclose(f); - return 2; + MALLOC(str, 2 * size + 1, return NULL); + + for (i = 0; i < size; i++) { + str[2 * i] = hex_digits[bytes[i] >> 4]; + str[2 * i + 1] = hex_digits[bytes[i] & 0x0f]; } - fclose(f); - return 0; + str[2 * size] = '\0'; + + return str; } -#endif /** Get the md5 sum of file. * @param filename name of the file @@ -829,28 +876,15 @@ static int sha2_file(const char *path, unsigned char output[32], int is224) char SYMEXPORT *alpm_compute_md5sum(const char *filename) { unsigned char output[16]; - char *md5sum; - int ret, i; ASSERT(filename != NULL, return NULL); - /* allocate 32 chars plus 1 for null */ - CALLOC(md5sum, 33, sizeof(char), return NULL); /* defined above for OpenSSL, otherwise defined in md5.h */ - ret = md5_file(filename, output); - - if(ret > 0) { - free(md5sum); + if(md5_file(filename, output) > 0) { return NULL; } - /* Convert the result to something readable */ - for (i = 0; i < 16; i++) { - /* sprintf is acceptable here because we know our output */ - sprintf(md5sum +(i * 2), "%02x", output[i]); - } - - return md5sum; + return hex_representation(output, 16); } /** Get the sha256 sum of file. @@ -861,39 +895,33 @@ char SYMEXPORT *alpm_compute_md5sum(const char *filename) char SYMEXPORT *alpm_compute_sha256sum(const char *filename) { unsigned char output[32]; - char *sha256sum; - int ret, i; ASSERT(filename != NULL, return NULL); - /* allocate 64 chars plus 1 for null */ - CALLOC(sha256sum, 65, sizeof(char), return NULL); /* defined above for OpenSSL, otherwise defined in sha2.h */ - ret = sha2_file(filename, output, 0); - - if(ret > 0) { - free(sha256sum); + if(sha2_file(filename, output, 0) > 0) { return NULL; } - /* Convert the result to something readable */ - for (i = 0; i < 32; i++) { - /* sprintf is acceptable here because we know our output */ - sprintf(sha256sum +(i * 2), "%02x", output[i]); - } - - return sha256sum; + return hex_representation(output, 32); } +/** Calculates a file's MD5 or SHA2 digest and compares it to an expected value. + * @param filepath path of the file to check + * @param expected hash value to compare against + * @param type digest type to use + * @return 0 if file matches the expected hash, 1 if they do not match, -1 on + * error + */ int _alpm_test_checksum(const char *filepath, const char *expected, - enum _alpm_csum type) + alpm_pkgvalidation_t type) { char *computed; int ret; - if(type == ALPM_CSUM_MD5) { + if(type == ALPM_PKG_VALIDATION_MD5SUM) { computed = alpm_compute_md5sum(filepath); - } else if(type == ALPM_CSUM_SHA256) { + } else if(type == ALPM_PKG_VALIDATION_SHA256SUM) { computed = alpm_compute_sha256sum(filepath); } else { return -1; @@ -912,18 +940,24 @@ int _alpm_test_checksum(const char *filepath, const char *expected, } /* Note: does NOT handle sparse files on purpose for speed. */ +/** TODO. + * Does not handle sparse files on purpose for speed. + * @param a + * @param b + * @return + */ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b) { - char *i = NULL; - int64_t offset; - int done = 0; - /* ensure we start populating our line buffer at the beginning */ b->line_offset = b->line; while(1) { + size_t block_remaining; + char *eol; + /* have we processed this entire block? */ if(b->block + b->block_size == b->block_offset) { + int64_t offset; if(b->ret == ARCHIVE_EOF) { /* reached end of archive on the last read, now we are out of data */ goto cleanup; @@ -933,20 +967,20 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b) b->ret = archive_read_data_block(a, (void *)&b->block, &b->block_size, &offset); b->block_offset = b->block; + block_remaining = b->block_size; /* error, cleanup */ if(b->ret < ARCHIVE_OK) { goto cleanup; } + } else { + block_remaining = b->block + b->block_size - b->block_offset; } - /* loop through the block looking for EOL characters */ - for(i = b->block_offset; i < (b->block + b->block_size); i++) { - /* check if read value was null or newline */ - if(*i == '\0' || *i == '\n') { - done = 1; - break; - } + /* look through the block looking for EOL characters */ + eol = memchr(b->block_offset, '\n', block_remaining); + if(!eol) { + eol = memchr(b->block_offset, '\0', block_remaining); } /* allocate our buffer, or ensure our existing one is big enough */ @@ -956,29 +990,32 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b) b->line_size = b->block_size + 1; b->line_offset = b->line; } else { - size_t needed = (size_t)((b->line_offset - b->line) - + (i - b->block_offset) + 1); + /* note: we know eol > b->block_offset and b->line_offset > b->line, + * so we know the result is unsigned and can fit in size_t */ + size_t new = eol ? (size_t)(eol - b->block_offset) : block_remaining; + size_t needed = (size_t)((b->line_offset - b->line) + new + 1); if(needed > b->max_line_size) { b->ret = -ERANGE; goto cleanup; } if(needed > b->line_size) { /* need to realloc + copy data to fit total length */ - char *new; - CALLOC(new, needed, sizeof(char), b->ret = -ENOMEM; goto cleanup); - memcpy(new, b->line, b->line_size); + char *new_line; + CALLOC(new_line, needed, sizeof(char), b->ret = -ENOMEM; goto cleanup); + memcpy(new_line, b->line, b->line_size); b->line_size = needed; - b->line_offset = new + (b->line_offset - b->line); + b->line_offset = new_line + (b->line_offset - b->line); free(b->line); - b->line = new; + b->line = new_line; } } - if(done) { - size_t len = (size_t)(i - b->block_offset); + if(eol) { + size_t len = (size_t)(eol - b->block_offset); memcpy(b->line_offset, b->block_offset, len); b->line_offset[len] = '\0'; - b->block_offset = ++i; + b->block_offset = eol + 1; + b->real_line_size = b->line_offset + len - b->line; /* this is the main return point; from here you can read b->line */ return ARCHIVE_OK; } else { @@ -986,11 +1023,12 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b) size_t len = (size_t)(b->block + b->block_size - b->block_offset); memcpy(b->line_offset, b->block_offset, len); b->line_offset += len; - b->block_offset = i; + b->block_offset = b->block + b->block_size; /* there was no new data, return what is left; saved ARCHIVE_EOF will be * returned on next call */ if(len == 0) { b->line_offset[0] = '\0'; + b->real_line_size = b->line_offset - b->line; return ARCHIVE_OK; } } @@ -1005,6 +1043,14 @@ cleanup: } } +/** Parse a full package specifier. + * @param target package specifier to parse, such as: "pacman-4.0.1-2", + * "pacman-4.01-2/", or "pacman-4.0.1-2/desc" + * @param name to hold package name + * @param version to hold package version + * @param name_hash to hold package name hash + * @return 0 on success, -1 on error + */ int _alpm_splitname(const char *target, char **name, char **version, unsigned long *name_hash) { @@ -1057,8 +1103,7 @@ int _alpm_splitname(const char *target, char **name, char **version, return 0; } -/** - * Hash the given string to an unsigned long value. +/** Hash the given string to an unsigned long value. * This is the standard sdbm hashing algorithm. * @param str string to hash * @return the hash value of the given string @@ -1072,12 +1117,17 @@ unsigned long _alpm_hash_sdbm(const char *str) return hash; } while((c = *str++)) { - hash = c + (hash << 6) + (hash << 16) - hash; + hash = c + hash * 65599; } return hash; } +/** Convert a string to a file offset. + * This parses bare positive integers only. + * @param line string to convert + * @return off_t on success, -1 on error + */ off_t _alpm_strtoofft(const char *line) { char *end; @@ -1089,13 +1139,13 @@ off_t _alpm_strtoofft(const char *line) return (off_t)-1; } result = strtoull(line, &end, 10); - if (result == 0 && end == line) { + if(result == 0 && end == line) { /* line was not a number */ return (off_t)-1; - } else if (result == ULLONG_MAX && errno == ERANGE) { + } else if(result == ULLONG_MAX && errno == ERANGE) { /* line does not fit in unsigned long long */ return (off_t)-1; - } else if (*end) { + } else if(*end) { /* line began with a number but has junk left over at the end */ return (off_t)-1; } @@ -1103,8 +1153,16 @@ off_t _alpm_strtoofft(const char *line) return (off_t)result; } -time_t _alpm_parsedate(const char *line) +/** Parses a date into an alpm_time_t struct. + * @param line date to parse + * @return time struct on success, 0 on error + */ +alpm_time_t _alpm_parsedate(const char *line) { + char *end; + long long result; + errno = 0; + if(isalpha((unsigned char)line[0])) { /* initialize to null in case of failure */ struct tm tmp_tm; @@ -1112,13 +1170,27 @@ time_t _alpm_parsedate(const char *line) setlocale(LC_TIME, "C"); strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm); setlocale(LC_TIME, ""); - return mktime(&tmp_tm); + return (alpm_time_t)mktime(&tmp_tm); + } + + result = strtoll(line, &end, 10); + if(result == 0 && end == line) { + /* line was not a number */ + errno = EINVAL; + return 0; + } else if(errno == ERANGE) { + /* line does not fit in long long */ + return 0; + } else if(*end) { + /* line began with a number but has junk left over at the end */ + errno = EINVAL; + return 0; } - return (time_t)atol(line); + + return (alpm_time_t)result; } -/** - * Wrapper around access() which takes a dir and file argument +/** Wrapper around access() which takes a dir and file argument * separately and generates an appropriate error message. * If dir is NULL file will be treated as the whole path. * @param handle an alpm handle @@ -1127,13 +1199,12 @@ time_t _alpm_parsedate(const char *line) * @param amode access mode as described in access() * @return int value returned by access() */ - int _alpm_access(alpm_handle_t *handle, const char *dir, const char *file, int amode) { size_t len = 0; int ret = 0; - if (dir) { + if(dir) { char *check_path; len = strlen(dir) + strlen(file) + 1; @@ -1148,19 +1219,19 @@ int _alpm_access(alpm_handle_t *handle, const char *dir, const char *file, int a } if(ret != 0) { - if (amode & R_OK) { + if(amode & R_OK) { _alpm_log(handle, ALPM_LOG_DEBUG, "\"%s%s\" is not readable: %s\n", dir, file, strerror(errno)); } - if (amode & W_OK) { + if(amode & W_OK) { _alpm_log(handle, ALPM_LOG_DEBUG, "\"%s%s\" is not writable: %s\n", dir, file, strerror(errno)); } - if (amode & X_OK) { + if(amode & X_OK) { _alpm_log(handle, ALPM_LOG_DEBUG, "\"%s%s\" is not executable: %s\n", dir, file, strerror(errno)); } - if (amode == F_OK) { + if(amode == F_OK) { _alpm_log(handle, ALPM_LOG_DEBUG, "\"%s%s\" does not exist: %s\n", dir, file, strerror(errno)); } @@ -1168,8 +1239,30 @@ int _alpm_access(alpm_handle_t *handle, const char *dir, const char *file, int a return ret; } +/** Checks whether a string matches a shell wildcard pattern. + * Wrapper around fnmatch. + * @param pattern pattern to match aganist + * @param string string to check against pattern + * @return 0 if string matches pattern, non-zero if they don't match and on + * error + */ +int _alpm_fnmatch(const void *pattern, const void *string) +{ + return fnmatch(pattern, string, 0); +} + +void _alpm_alloc_fail(size_t size) +{ + fprintf(stderr, "alloc failure: could not allocate %zd bytes\n", size); +} + #ifndef HAVE_STRNDUP /* A quick and dirty implementation derived from glibc */ +/** Determines the length of a fixed-size string. + * @param s string to be measured + * @param max maximum number of characters to search for the string end + * @return length of s or max, whichever is smaller + */ static size_t strnlen(const char *s, size_t max) { register const char *p; @@ -1177,6 +1270,12 @@ static size_t strnlen(const char *s, size_t max) return (p - s); } +/** Copies a string. + * Returned string needs to be freed + * @param s string to be copied + * @param n maximum number of characters to copy + * @return pointer to the new string on success, NULL on error + */ char *strndup(const char *s, size_t n) { size_t len = strnlen(s, n); diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h index 26fa9044..9bcd59e1 100644 --- a/lib/libalpm/util.h +++ b/lib/libalpm/util.h @@ -1,7 +1,7 @@ /* * util.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> * Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu> @@ -24,8 +24,6 @@ #ifndef _ALPM_UTIL_H #define _ALPM_UTIL_H -#include "config.h" - #include "alpm_list.h" #include "alpm.h" #include "package.h" /* alpm_pkg_t */ @@ -35,11 +33,13 @@ #include <string.h> #include <stdarg.h> #include <stddef.h> /* size_t */ -#include <time.h> +#include <sys/types.h> #include <sys/stat.h> /* struct stat */ -#include <archive.h> /* struct archive */ #include <math.h> /* fabs */ #include <float.h> /* DBL_EPSILON */ +#include <fcntl.h> /* open, close */ + +#include <archive.h> /* struct archive */ #ifdef ENABLE_NLS #include <libintl.h> /* here so it doesn't need to be included elsewhere */ @@ -49,13 +49,13 @@ #define _(s) s #endif -#define ALLOC_FAIL(s) do { fprintf(stderr, "alloc failure: could not allocate %zd bytes\n", s); } while(0) +void _alpm_alloc_fail(size_t size); -#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 MALLOC(p, s, action) do { p = malloc(s); if(p == NULL) { _alpm_alloc_fail(s); action; } } while(0) +#define CALLOC(p, l, s, action) do { p = calloc(l, s); if(p == NULL) { _alpm_alloc_fail(l * 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 STRNDUP(r, s, l, action) do { if(s != NULL) { r = strndup(s, l); if(r == NULL) { ALLOC_FAIL(strlen(s)); action; } } else { r = NULL; } } while(0) +#define STRDUP(r, s, action) do { if(s != NULL) { r = strdup(s); if(r == NULL) { _alpm_alloc_fail(strlen(s)); action; } } else { r = NULL; } } while(0) +#define STRNDUP(r, s, l, action) do { if(s != NULL) { r = strndup(s, l); if(r == NULL) { _alpm_alloc_fail(l); action; } } else { r = NULL; } } while(0) #define FREE(p) do { free(p); p = NULL; } while(0) @@ -82,6 +82,13 @@ #define ALPM_BUFFER_SIZE 8192 #endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define OPEN(fd, path, flags) do { fd = open(path, flags | O_BINARY); } while(fd == -1 && errno == EINTR) +#define CLOSE(fd) do { int _ret; do { _ret = close(fd); } while(_ret == -1 && errno == EINTR); } while(0) + /** * Used as a buffer/state holder for _alpm_archive_fgets(). */ @@ -90,6 +97,7 @@ struct archive_read_buffer { char *line_offset; size_t line_size; size_t max_line_size; + size_t real_line_size; char *block; char *block_offset; @@ -98,39 +106,37 @@ struct archive_read_buffer { int ret; }; -enum _alpm_csum { - ALPM_CSUM_MD5, - ALPM_CSUM_SHA256, -}; - 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); -char *_alpm_strtrim(char *str); -size_t _alpm_strip_newline(char *str); +size_t _alpm_strip_newline(char *str, size_t len); + +int _alpm_open_archive(alpm_handle_t *handle, const char *path, + struct stat *buf, struct archive **archive, alpm_errno_t error); int _alpm_unpack_single(alpm_handle_t *handle, const char *archive, const char *prefix, const char *filename); int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix, alpm_list_t *list, int breakfirst); -int _alpm_rmrf(const char *path); + ssize_t _alpm_files_in_directory(alpm_handle_t *handle, const char *path, int full_count); int _alpm_logaction(alpm_handle_t *handle, const char *fmt, va_list args); -int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[]); +int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[]); int _alpm_ldconfig(alpm_handle_t *handle); int _alpm_str_cmp(const void *s1, const void *s2); char *_alpm_filecache_find(alpm_handle_t *handle, const char *filename); const char *_alpm_filecache_setup(alpm_handle_t *handle); int _alpm_lstat(const char *path, struct stat *buf); -int _alpm_test_checksum(const char *filepath, const char *expected, enum _alpm_csum type); +int _alpm_test_checksum(const char *filepath, const char *expected, alpm_pkgvalidation_t type); int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b); int _alpm_splitname(const char *target, char **name, char **version, unsigned long *name_hash); unsigned long _alpm_hash_sdbm(const char *str); off_t _alpm_strtoofft(const char *line); -time_t _alpm_parsedate(const char *line); +alpm_time_t _alpm_parsedate(const char *line); int _alpm_raw_cmp(const char *first, const char *second); int _alpm_raw_ncmp(const char *first, const char *second, size_t max); int _alpm_access(alpm_handle_t *handle, const char *dir, const char *file, int amode); +int _alpm_fnmatch(const void *pattern, const void *string); #ifndef HAVE_STRSEP char *strsep(char **, const char *); diff --git a/lib/libalpm/version.c b/lib/libalpm/version.c index 6b65a413..269a7016 100644 --- a/lib/libalpm/version.c +++ b/lib/libalpm/version.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,8 +15,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <string.h> #include <ctype.h> diff --git a/acinclude.m4 b/m4/acinclude.m4 index df4f83a4..f57a515e 100644 --- a/acinclude.m4 +++ b/m4/acinclude.m4 @@ -40,11 +40,15 @@ AC_DEFUN([GCC_STACK_PROTECT_CC],[ dnl GCC_FORTIFY_SOURCE_CC dnl checks -D_FORTIFY_SOURCE with the C compiler, if it exists then updates -dnl CFLAGS +dnl CPPFLAGS AC_DEFUN([GCC_FORTIFY_SOURCE_CC],[ AC_LANG_ASSERT(C) if test "X$CC" != "X"; then AC_MSG_CHECKING(for FORTIFY_SOURCE support) + fs_old_cppflags="$CPPFLAGS" + fs_old_cflags="$CFLAGS" + CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2" + CFLAGS="$CFLAGS -Werror" AC_TRY_COMPILE([#include <features.h>], [ int main() { #if !(__GNUC_PREREQ (4, 1) ) @@ -54,10 +58,12 @@ AC_DEFUN([GCC_FORTIFY_SOURCE_CC],[ } ], [ AC_MSG_RESULT(yes) - CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" + CFLAGS="$df_old_cflags" ], [ AC_MSG_RESULT(no) - ]) + CPPFLAGS="$df_old_cppflags" + CFLAGS="$df_old_cflags" + ]) fi ]) @@ -101,6 +107,26 @@ AC_DEFUN([GCC_GNU89_INLINE_CC],[ fi ]) +dnl CFLAGS_ADD(PARAMETER, VARIABLE) +dnl Adds parameter to VARIABLE if the compiler supports it. For example, +dnl CFLAGS_ADD([-Wall],[WARN_FLAGS]). +AC_DEFUN([CFLAGS_ADD], +[AS_VAR_PUSHDEF([my_cflags], [cflags_cv_warn_$1])dnl +AC_CACHE_CHECK([whether compiler handles $1], [my_cflags], [ + save_CFLAGS="$CFLAGS" + CFLAGS="${CFLAGS} $1" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], + [AS_VAR_SET([my_cflags], [yes])], + [AS_VAR_SET([my_cflags], [no])]) + CFLAGS="$save_CFLAGS" +]) +AS_VAR_PUSHDEF([new_cflags], [[$2]])dnl +AS_VAR_IF([my_cflags], [yes], [AS_VAR_APPEND([new_cflags], [" $1"])]) +AS_VAR_POPDEF([new_cflags])dnl +AS_VAR_POPDEF([my_cflags])dnl +m4_ifval([$2], [AS_LITERAL_IF([$2], [AC_SUBST([$2])], [])])dnl +]) + dnl Checks for getmntinfo and determines whether it uses statfs or statvfs AC_DEFUN([FS_STATS_TYPE], [AC_CACHE_CHECK([filesystem statistics type], fs_stats_cv_type, diff --git a/m4/gpgme.m4 b/m4/gpgme.m4 new file mode 100644 index 00000000..44bf43cb --- /dev/null +++ b/m4/gpgme.m4 @@ -0,0 +1,307 @@ +# gpgme.m4 - autoconf macro to detect GPGME. +# Copyright (C) 2002, 2003, 2004 g10 Code GmbH +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This file is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + +AC_DEFUN([_AM_PATH_GPGME_CONFIG], +[ AC_ARG_WITH(gpgme-prefix, + AC_HELP_STRING([--with-gpgme-prefix=PFX], + [prefix where GPGME is installed (optional)]), + gpgme_config_prefix="$withval", gpgme_config_prefix="") + if test "x$gpgme_config_prefix" != x ; then + GPGME_CONFIG="$gpgme_config_prefix/bin/gpgme-config" + fi + AC_PATH_PROG(GPGME_CONFIG, gpgme-config, no) + + if test "$GPGME_CONFIG" != "no" ; then + gpgme_version=`$GPGME_CONFIG --version` + fi + gpgme_version_major=`echo $gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\1/'` + gpgme_version_minor=`echo $gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\2/'` + gpgme_version_micro=`echo $gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\).*/\3/'` +]) + +dnl AM_PATH_GPGME([MINIMUM-VERSION, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl Test for libgpgme and define GPGME_CFLAGS and GPGME_LIBS. +dnl +AC_DEFUN([AM_PATH_GPGME], +[ AC_REQUIRE([_AM_PATH_GPGME_CONFIG])dnl + tmp=ifelse([$1], ,1:0.4.2,$1) + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_gpgme_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_gpgme_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_gpgme_api=0 + min_gpgme_version="$tmp" + fi + + AC_MSG_CHECKING(for GPGME - version >= $min_gpgme_version) + ok=no + if test "$GPGME_CONFIG" != "no" ; then + req_major=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + req_minor=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + req_micro=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + if test "$gpgme_version_major" -gt "$req_major"; then + ok=yes + else + if test "$gpgme_version_major" -eq "$req_major"; then + if test "$gpgme_version_minor" -gt "$req_minor"; then + ok=yes + else + if test "$gpgme_version_minor" -eq "$req_minor"; then + if test "$gpgme_version_micro" -ge "$req_micro"; then + ok=yes + fi + fi + fi + fi + fi + fi + if test $ok = yes; then + # If we have a recent GPGME, we should also check that the + # API is compatible. + if test "$req_gpgme_api" -gt 0 ; then + tmp=`$GPGME_CONFIG --api-version 2>/dev/null || echo 0` + if test "$tmp" -gt 0 ; then + if test "$req_gpgme_api" -ne "$tmp" ; then + ok=no + fi + fi + fi + fi + if test $ok = yes; then + GPGME_CFLAGS=`$GPGME_CONFIG --cflags` + GPGME_LIBS=`$GPGME_CONFIG --libs` + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + GPGME_CFLAGS="" + GPGME_LIBS="" + AC_MSG_RESULT(no) + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GPGME_CFLAGS) + AC_SUBST(GPGME_LIBS) +]) + +dnl AM_PATH_GPGME_PTH([MINIMUM-VERSION, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl Test for libgpgme and define GPGME_PTH_CFLAGS and GPGME_PTH_LIBS. +dnl +AC_DEFUN([AM_PATH_GPGME_PTH], +[ AC_REQUIRE([_AM_PATH_GPGME_CONFIG])dnl + tmp=ifelse([$1], ,1:0.4.2,$1) + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_gpgme_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_gpgme_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_gpgme_api=0 + min_gpgme_version="$tmp" + fi + + AC_MSG_CHECKING(for GPGME Pth - version >= $min_gpgme_version) + ok=no + if test "$GPGME_CONFIG" != "no" ; then + if `$GPGME_CONFIG --thread=pth 2> /dev/null` ; then + req_major=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + req_minor=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + req_micro=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + if test "$gpgme_version_major" -gt "$req_major"; then + ok=yes + else + if test "$gpgme_version_major" -eq "$req_major"; then + if test "$gpgme_version_minor" -gt "$req_minor"; then + ok=yes + else + if test "$gpgme_version_minor" -eq "$req_minor"; then + if test "$gpgme_version_micro" -ge "$req_micro"; then + ok=yes + fi + fi + fi + fi + fi + fi + fi + if test $ok = yes; then + # If we have a recent GPGME, we should also check that the + # API is compatible. + if test "$req_gpgme_api" -gt 0 ; then + tmp=`$GPGME_CONFIG --api-version 2>/dev/null || echo 0` + if test "$tmp" -gt 0 ; then + if test "$req_gpgme_api" -ne "$tmp" ; then + ok=no + fi + fi + fi + fi + if test $ok = yes; then + GPGME_PTH_CFLAGS=`$GPGME_CONFIG --thread=pth --cflags` + GPGME_PTH_LIBS=`$GPGME_CONFIG --thread=pth --libs` + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + GPGME_PTH_CFLAGS="" + GPGME_PTH_LIBS="" + AC_MSG_RESULT(no) + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GPGME_PTH_CFLAGS) + AC_SUBST(GPGME_PTH_LIBS) +]) + +dnl AM_PATH_GPGME_PTHREAD([MINIMUM-VERSION, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl Test for libgpgme and define GPGME_PTHREAD_CFLAGS +dnl and GPGME_PTHREAD_LIBS. +dnl +AC_DEFUN([AM_PATH_GPGME_PTHREAD], +[ AC_REQUIRE([_AM_PATH_GPGME_CONFIG])dnl + tmp=ifelse([$1], ,1:0.4.2,$1) + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_gpgme_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_gpgme_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_gpgme_api=0 + min_gpgme_version="$tmp" + fi + + AC_MSG_CHECKING(for GPGME pthread - version >= $min_gpgme_version) + ok=no + if test "$GPGME_CONFIG" != "no" ; then + if `$GPGME_CONFIG --thread=pthread 2> /dev/null` ; then + req_major=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + req_minor=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + req_micro=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + if test "$gpgme_version_major" -gt "$req_major"; then + ok=yes + else + if test "$gpgme_version_major" -eq "$req_major"; then + if test "$gpgme_version_minor" -gt "$req_minor"; then + ok=yes + else + if test "$gpgme_version_minor" -eq "$req_minor"; then + if test "$gpgme_version_micro" -ge "$req_micro"; then + ok=yes + fi + fi + fi + fi + fi + fi + fi + if test $ok = yes; then + # If we have a recent GPGME, we should also check that the + # API is compatible. + if test "$req_gpgme_api" -gt 0 ; then + tmp=`$GPGME_CONFIG --api-version 2>/dev/null || echo 0` + if test "$tmp" -gt 0 ; then + if test "$req_gpgme_api" -ne "$tmp" ; then + ok=no + fi + fi + fi + fi + if test $ok = yes; then + GPGME_PTHREAD_CFLAGS=`$GPGME_CONFIG --thread=pthread --cflags` + GPGME_PTHREAD_LIBS=`$GPGME_CONFIG --thread=pthread --libs` + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + GPGME_PTHREAD_CFLAGS="" + GPGME_PTHREAD_LIBS="" + AC_MSG_RESULT(no) + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GPGME_PTHREAD_CFLAGS) + AC_SUBST(GPGME_PTHREAD_LIBS) +]) + + +dnl AM_PATH_GPGME_GLIB([MINIMUM-VERSION, +dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]]) +dnl Test for libgpgme-glib and define GPGME_GLIB_CFLAGS and GPGME_GLIB_LIBS. +dnl +AC_DEFUN([AM_PATH_GPGME_GLIB], +[ AC_REQUIRE([_AM_PATH_GPGME_CONFIG])dnl + tmp=ifelse([$1], ,1:0.4.2,$1) + if echo "$tmp" | grep ':' >/dev/null 2>/dev/null ; then + req_gpgme_api=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\1/'` + min_gpgme_version=`echo "$tmp" | sed 's/\(.*\):\(.*\)/\2/'` + else + req_gpgme_api=0 + min_gpgme_version="$tmp" + fi + + AC_MSG_CHECKING(for GPGME - version >= $min_gpgme_version) + ok=no + if test "$GPGME_CONFIG" != "no" ; then + req_major=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + req_minor=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + req_micro=`echo $min_gpgme_version | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + if test "$gpgme_version_major" -gt "$req_major"; then + ok=yes + else + if test "$gpgme_version_major" -eq "$req_major"; then + if test "$gpgme_version_minor" -gt "$req_minor"; then + ok=yes + else + if test "$gpgme_version_minor" -eq "$req_minor"; then + if test "$gpgme_version_micro" -ge "$req_micro"; then + ok=yes + fi + fi + fi + fi + fi + fi + if test $ok = yes; then + # If we have a recent GPGME, we should also check that the + # API is compatible. + if test "$req_gpgme_api" -gt 0 ; then + tmp=`$GPGME_CONFIG --api-version 2>/dev/null || echo 0` + if test "$tmp" -gt 0 ; then + if test "$req_gpgme_api" -ne "$tmp" ; then + ok=no + fi + fi + fi + fi + if test $ok = yes; then + GPGME_GLIB_CFLAGS=`$GPGME_CONFIG --glib --cflags` + GPGME_GLIB_LIBS=`$GPGME_CONFIG --glib --libs` + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + GPGME_GLIB_CFLAGS="" + GPGME_GLIB_LIBS="" + AC_MSG_RESULT(no) + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GPGME_GLIB_CFLAGS) + AC_SUBST(GPGME_GLIB_LIBS) +]) + diff --git a/m4/libcurl.m4 b/m4/libcurl.m4 deleted file mode 100644 index 01a0575c..00000000 --- a/m4/libcurl.m4 +++ /dev/null @@ -1,250 +0,0 @@ -# LIBCURL_CHECK_CONFIG ([DEFAULT-ACTION], [MINIMUM-VERSION], -# [ACTION-IF-YES], [ACTION-IF-NO]) -# ---------------------------------------------------------- -# David Shaw <dshaw@jabberwocky.com> May-09-2006 -# -# Checks for libcurl. DEFAULT-ACTION is the string yes or no to -# specify whether to default to --with-libcurl or --without-libcurl. -# If not supplied, DEFAULT-ACTION is yes. MINIMUM-VERSION is the -# minimum version of libcurl to accept. Pass the version as a regular -# version number like 7.10.1. If not supplied, any version is -# accepted. ACTION-IF-YES is a list of shell commands to run if -# libcurl was successfully found and passed the various tests. -# ACTION-IF-NO is a list of shell commands that are run otherwise. -# Note that using --without-libcurl does run ACTION-IF-NO. -# -# This macro #defines HAVE_LIBCURL if a working libcurl setup is -# found, and sets @LIBCURL@ and @LIBCURL_CPPFLAGS@ to the necessary -# values. Other useful defines are LIBCURL_FEATURE_xxx where xxx are -# the various features supported by libcurl, and LIBCURL_PROTOCOL_yyy -# where yyy are the various protocols supported by libcurl. Both xxx -# and yyy are capitalized. See the list of AH_TEMPLATEs at the top of -# the macro for the complete list of possible defines. Shell -# variables $libcurl_feature_xxx and $libcurl_protocol_yyy are also -# defined to 'yes' for those features and protocols that were found. -# Note that xxx and yyy keep the same capitalization as in the -# curl-config list (e.g. it's "HTTP" and not "http"). -# -# Users may override the detected values by doing something like: -# LIBCURL="-lcurl" LIBCURL_CPPFLAGS="-I/usr/myinclude" ./configure -# -# For the sake of sanity, this macro assumes that any libcurl that is -# found is after version 7.7.2, the first version that included the -# curl-config script. Note that it is very important for people -# packaging binary versions of libcurl to include this script! -# Without curl-config, we can only guess what protocols are available, -# or use curl_version_info to figure it out at runtime. - -AC_DEFUN([LIBCURL_CHECK_CONFIG], -[ - AH_TEMPLATE([LIBCURL_FEATURE_SSL],[Defined if libcurl supports SSL]) - AH_TEMPLATE([LIBCURL_FEATURE_KRB4],[Defined if libcurl supports KRB4]) - AH_TEMPLATE([LIBCURL_FEATURE_IPV6],[Defined if libcurl supports IPv6]) - AH_TEMPLATE([LIBCURL_FEATURE_LIBZ],[Defined if libcurl supports libz]) - AH_TEMPLATE([LIBCURL_FEATURE_ASYNCHDNS],[Defined if libcurl supports AsynchDNS]) - AH_TEMPLATE([LIBCURL_FEATURE_IDN],[Defined if libcurl supports IDN]) - AH_TEMPLATE([LIBCURL_FEATURE_SSPI],[Defined if libcurl supports SSPI]) - AH_TEMPLATE([LIBCURL_FEATURE_NTLM],[Defined if libcurl supports NTLM]) - - AH_TEMPLATE([LIBCURL_PROTOCOL_HTTP],[Defined if libcurl supports HTTP]) - AH_TEMPLATE([LIBCURL_PROTOCOL_HTTPS],[Defined if libcurl supports HTTPS]) - AH_TEMPLATE([LIBCURL_PROTOCOL_FTP],[Defined if libcurl supports FTP]) - AH_TEMPLATE([LIBCURL_PROTOCOL_FTPS],[Defined if libcurl supports FTPS]) - AH_TEMPLATE([LIBCURL_PROTOCOL_FILE],[Defined if libcurl supports FILE]) - AH_TEMPLATE([LIBCURL_PROTOCOL_TELNET],[Defined if libcurl supports TELNET]) - AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP]) - AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT]) - AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP]) - AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP]) - AH_TEMPLATE([LIBCURL_PROTOCOL_POP3],[Defined if libcurl supports POP3]) - AH_TEMPLATE([LIBCURL_PROTOCOL_IMAP],[Defined if libcurl supports IMAP]) - AH_TEMPLATE([LIBCURL_PROTOCOL_SMTP],[Defined if libcurl supports SMTP]) - - AC_ARG_WITH(libcurl, - AC_HELP_STRING([--with-libcurl=PREFIX],[look for the curl library in PREFIX/lib and headers in PREFIX/include]), - [_libcurl_with=$withval],[_libcurl_with=ifelse([$1],,[yes],[$1])]) - - if test "$_libcurl_with" != "no" ; then - - AC_PROG_AWK - - _libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'" - - _libcurl_try_link=yes - - if test -d "$_libcurl_with" ; then - LIBCURL_CPPFLAGS="-I$withval/include" - _libcurl_ldflags="-L$withval/lib" - AC_PATH_PROG([_libcurl_config],[curl-config],[], - ["$withval/bin"]) - else - AC_PATH_PROG([_libcurl_config],[curl-config],[],[$PATH]) - fi - - if test x$_libcurl_config != "x" ; then - AC_CACHE_CHECK([for the version of libcurl], - [libcurl_cv_lib_curl_version], - [libcurl_cv_lib_curl_version=`$_libcurl_config --version | $AWK '{print $[]2}'`]) - - _libcurl_version=`echo $libcurl_cv_lib_curl_version | $_libcurl_version_parse` - _libcurl_wanted=`echo ifelse([$2],,[0],[$2]) | $_libcurl_version_parse` - - if test $_libcurl_wanted -gt 0 ; then - AC_CACHE_CHECK([for libcurl >= version $2], - [libcurl_cv_lib_version_ok], - [ - if test $_libcurl_version -ge $_libcurl_wanted ; then - libcurl_cv_lib_version_ok=yes - else - libcurl_cv_lib_version_ok=no - fi - ]) - fi - - if test $_libcurl_wanted -eq 0 || test x$libcurl_cv_lib_version_ok = xyes ; then - if test x"$LIBCURL_CPPFLAGS" = "x" ; then - LIBCURL_CPPFLAGS=`$_libcurl_config --cflags` - fi - if test x"$LIBCURL" = "x" ; then - LIBCURL=`$_libcurl_config --libs` - - # This is so silly, but Apple actually has a bug in their - # curl-config script. Fixed in Tiger, but there are still - # lots of Panther installs around. - case "${host}" in - powerpc-apple-darwin7*) - LIBCURL=`echo $LIBCURL | sed -e 's|-arch i386||g'` - ;; - esac - fi - - # All curl-config scripts support --feature - _libcurl_features=`$_libcurl_config --feature` - - # Is it modern enough to have --protocols? (7.12.4) - if test $_libcurl_version -ge 461828 ; then - _libcurl_protocols=`$_libcurl_config --protocols` - fi - else - _libcurl_try_link=no - fi - - unset _libcurl_wanted - fi - - if test $_libcurl_try_link = yes ; then - - # we didn't find curl-config, so let's see if the user-supplied - # link line (or failing that, "-lcurl") is enough. - LIBCURL=${LIBCURL-"$_libcurl_ldflags -lcurl"} - - AC_CACHE_CHECK([whether libcurl is usable], - [libcurl_cv_lib_curl_usable], - [ - _libcurl_save_cppflags=$CPPFLAGS - CPPFLAGS="$LIBCURL_CPPFLAGS $CPPFLAGS" - _libcurl_save_libs=$LIBS - LIBS="$LIBCURL $LIBS" - - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <curl/curl.h>],[ -/* Try and use a few common options to force a failure if we are - missing symbols or can't link. */ -int x; -curl_easy_setopt(NULL,CURLOPT_URL,NULL); -x=CURL_ERROR_SIZE; -x=CURLOPT_WRITEFUNCTION; -x=CURLOPT_FILE; -x=CURLOPT_ERRORBUFFER; -x=CURLOPT_STDERR; -x=CURLOPT_VERBOSE; -])],libcurl_cv_lib_curl_usable=yes,libcurl_cv_lib_curl_usable=no) - - CPPFLAGS=$_libcurl_save_cppflags - LIBS=$_libcurl_save_libs - unset _libcurl_save_cppflags - unset _libcurl_save_libs - ]) - - if test $libcurl_cv_lib_curl_usable = yes ; then - - # Does curl_free() exist in this version of libcurl? - # If not, fake it with free() - - _libcurl_save_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $LIBCURL_CPPFLAGS" - _libcurl_save_libs=$LIBS - LIBS="$LIBS $LIBCURL" - - AC_CHECK_FUNC(curl_free,, - AC_DEFINE(curl_free,free, - [Define curl_free() as free() if our version of curl lacks curl_free.])) - - CPPFLAGS=$_libcurl_save_cppflags - LIBS=$_libcurl_save_libs - unset _libcurl_save_cppflags - unset _libcurl_save_libs - - AC_DEFINE(HAVE_LIBCURL,1, - [Define to 1 if you have a functional curl library.]) - AC_SUBST(LIBCURL_CPPFLAGS) - AC_SUBST(LIBCURL) - - for _libcurl_feature in $_libcurl_features ; do - AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1]) - eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes - done - - if test "x$_libcurl_protocols" = "x" ; then - - # We don't have --protocols, so just assume that all - # protocols are available - _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP" - - if test x$libcurl_feature_SSL = xyes ; then - _libcurl_protocols="$_libcurl_protocols HTTPS" - - # FTPS wasn't standards-compliant until version - # 7.11.0 (0x070b00 == 461568) - if test $_libcurl_version -ge 461568; then - _libcurl_protocols="$_libcurl_protocols FTPS" - fi - fi - - # RTSP, IMAP, POP3 and SMTP were added in - # 7.20.0 (0x071400 == 463872) - if test $_libcurl_version -ge 463872; then - _libcurl_protocols="$_libcurl_protocols RTSP IMAP POP3 SMTP" - fi - fi - - for _libcurl_protocol in $_libcurl_protocols ; do - AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_protocol_$_libcurl_protocol),[1]) - eval AS_TR_SH(libcurl_protocol_$_libcurl_protocol)=yes - done - else - unset LIBCURL - unset LIBCURL_CPPFLAGS - fi - fi - - unset _libcurl_try_link - unset _libcurl_version_parse - unset _libcurl_config - unset _libcurl_feature - unset _libcurl_features - unset _libcurl_protocol - unset _libcurl_protocols - unset _libcurl_version - unset _libcurl_ldflags - fi - - if test x$_libcurl_with = xno || test x$libcurl_cv_lib_curl_usable != xyes ; then - # This is the IF-NO path - ifelse([$4],,:,[$4]) - else - # This is the IF-YES path - ifelse([$3],,:,[$3]) - fi - - unset _libcurl_with -])dnl diff --git a/m4/pkg.m4 b/m4/pkg.m4 new file mode 100644 index 00000000..5152a4b1 --- /dev/null +++ b/m4/pkg.m4 @@ -0,0 +1,159 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 1 (pkg-config-0.24) +# +# Copyright © 2004 Scott James Remnant <scott@netsplit.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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +# only at the first occurence in configure.ac, so if the first place +# it's called might be skipped (such as if it is within an "if", you +# have to call PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl +]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])# PKG_CHECK_MODULES diff --git a/proto/PKGBUILD-split.proto b/proto/PKGBUILD-split.proto index 763cb86c..f873db60 100644 --- a/proto/PKGBUILD-split.proto +++ b/proto/PKGBUILD-split.proto @@ -46,6 +46,7 @@ package_pkg1() { epoch= pkgdesc="" arch=() + url="" license=() groups=() depends=() diff --git a/scripts/.gitignore b/scripts/.gitignore index 21b671c0..9e403bfb 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -3,7 +3,6 @@ pacman-db-upgrade pacman-key pacman-optimize pkgdelta -rankmirrors repo-add repo-elephant repo-remove diff --git a/scripts/Makefile.am b/scripts/Makefile.am index d89fd306..29c81aa5 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -4,7 +4,9 @@ AUTOMAKE_OPTIONS = std-options SUBDIRS = po bin_SCRIPTS = \ - $(OURSCRIPTS) + $(OURSCRIPTS) \ + repo-remove \ + repo-elephant OURSCRIPTS = \ makepkg \ @@ -12,7 +14,6 @@ OURSCRIPTS = \ pacman-key \ pacman-optimize \ pkgdelta \ - rankmirrors \ repo-add EXTRA_DIST = \ @@ -21,13 +22,14 @@ EXTRA_DIST = \ pacman-key.sh.in \ pacman-optimize.sh.in \ pkgdelta.sh.in \ - rankmirrors.sh.in \ repo-add.sh.in \ $(LIBRARY) LIBRARY = \ library/output_format.sh \ - library/parse_options.sh + library/parseopts.sh \ + library/human_to_size.sh \ + library/size_to_human.sh # Files that should be removed, but which Automake does not know. MOSTLYCLEANFILES = $(bin_SCRIPTS) @@ -51,6 +53,7 @@ edit = sed \ -e 's|@PACKAGE_BUGREPORT[@]|$(PACKAGE_BUGREPORT)|g' \ -e 's|@PACKAGE_NAME[@]|$(PACKAGE_NAME)|g' \ -e 's|@BUILDSCRIPT[@]|$(BUILDSCRIPT)|g' \ + -e "s|@INODECMD[@]|$(INODECMD)|g" \ -e 's|@SIZECMD[@]|$(SIZECMD)|g' \ -e 's|@SEDINPLACE[@]|$(SEDINPLACE)|g' \ -e 's|@DUPATH[@]|$(DUPATH)|g' \ @@ -60,18 +63,15 @@ edit = sed \ ## All the scripts depend on Makefile so that they are rebuilt when the ## prefix etc. changes. Use chmod -w to prevent people from editing the ## wrong file by accident. -# two 'test' lines- make sure we can handle both sh and py type scripts -# third 'test' line- make sure one of the two checks succeeded $(OURSCRIPTS): Makefile - @echo ' ' GEN $@; - @$(RM) $@ - @test -f $(srcdir)/$@.sh.in && m4 -P -I $(srcdir) $(srcdir)/$@.sh.in | $(edit) >$@ - @chmod +x $@ - @chmod a-w $@ + $(AM_V_at)$(RM) $@ + $(AM_V_GEN)test -f $(srcdir)/$@.sh.in && m4 -P -I $(srcdir) $(srcdir)/$@.sh.in | $(edit) >$@ + $(AM_V_at)chmod +x,a-w $@ + @$(BASH_SHELL) -O extglob -n $@ makepkg: \ $(srcdir)/makepkg.sh.in \ - $(srcdir)/library/parse_options.sh + $(srcdir)/library/parseopts.sh pacman-db-upgrade: \ $(srcdir)/pacman-db-upgrade.sh.in \ @@ -80,7 +80,7 @@ pacman-db-upgrade: \ pacman-key: \ $(srcdir)/pacman-key.sh.in \ $(srcdir)/library/output_format.sh \ - $(srcdir)/library/parse_options.sh + $(srcdir)/library/parseopts.sh pacman-optimize: \ $(srcdir)/pacman-optimize.sh.in \ @@ -88,21 +88,20 @@ pacman-optimize: \ pkgdelta: \ $(srcdir)/pkgdelta.sh.in \ - $(srcdir)/library/output_format.sh - -rankmirrors: $(srcdir)/rankmirrors.sh.in + $(srcdir)/library/output_format.sh \ + $(srcdir)/library/parseopts.sh repo-add: \ $(srcdir)/repo-add.sh.in \ $(srcdir)/library/output_format.sh repo-remove: $(srcdir)/repo-add.sh.in - $(RM) repo-remove - $(LN_S) repo-add repo-remove + $(AM_V_at)$(RM) repo-remove + $(AM_V_at)$(LN_S) repo-add repo-remove repo-elephant: $(srcdir)/repo-add.sh.in - $(RM) repo-elephant - $(LN_S) repo-add repo-elephant + $(AM_V_at)$(RM) repo-elephant + $(AM_V_at)$(LN_S) repo-add repo-elephant install-data-hook: cd $(DESTDIR)$(bindir) && \ diff --git a/scripts/library/README b/scripts/library/README index 1e9c962b..0fa0f847 100644 --- a/scripts/library/README +++ b/scripts/library/README @@ -8,8 +8,34 @@ and can be silenced by defining 'QUIET'. The 'warning' and 'error' functions print to stderr with the appropriate prefix added to the message. -parse_options.sh: -A getopt replacement to avoids portability issues, in particular the -lack of long option name support in the default getopt provided by some -platforms. -Usage: parse_option $SHORT_OPTS $LONG_OPTS "$@" +parseopts.sh: +A getopt_long-like parser which portably supports longopts and shortopts +with some GNU extensions. It does not allow for options with optional +arguments. For both short and long opts, options requiring an argument +should be suffixed with a colon. After the first argument containing +the short opts, any number of valid long opts may be be passed. The end +of the options delimiter must then be added, followed by the user arguments +to the calling program. + +Reccommended Usage: + OPT_SHORT='fb:z' + OPT_LONG=('foo' 'bar:' 'baz') + if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then + exit 1 + fi + set -- "${OPTRET[@]}" +Returns: + 0: parse success + 1: parse failure (error message supplied) + +human_to_size.sh: +A function to convert human readable sizes (such as "5.3 GiB") to raw byte +equivalents. base10 and base2 suffixes are supported, case sensitively. If +successful, the converted byte value is written to stdout and the function +returns 0. If an error occurs, nothing in written and the function returns 1. +Results may be inaccurate when using a broken implementation of awk, such +as mawk or busybox awk. + +size_to_human.sh: +The reverse of human_to_size, this function takes an integer byte size and +prints its in human readable format, with SI prefixes (e.g. MiB, TiB). diff --git a/scripts/library/human_to_size.sh b/scripts/library/human_to_size.sh new file mode 100644 index 00000000..11613207 --- /dev/null +++ b/scripts/library/human_to_size.sh @@ -0,0 +1,51 @@ +human_to_size() { + awk -v human="$1" ' + function trim(s) { + gsub(/^[[:space:]]+|[[:space:]]+$/, "", s) + return s + } + + function parse_units(units) { + if (!units || units == "B") + return 1 + if (match(units, /^.iB$/)) + return 1024 + if (match(units, /^.B$/)) + return 1000 + if (length(units) == 1) + return 1024 + + # parse failure: invalid base + return -1 + } + + function parse_scale(s) { + return index("BKMGTPE", s) - 1 + } + + function isnumeric(string) { + return match(string, /^[-+]?[[:digit:]]*(\.[[:digit:]]*)?/) + } + + BEGIN { + # peel off the leading number as the size, fail on invalid number + human = trim(human) + if (isnumeric(human)) + size = substr(human, RSTART, RLENGTH) + else + exit 1 + + # the trimmed remainder is assumed to be the units + units = trim(substr(human, RLENGTH + 1)) + + base = parse_units(units) + if (base < 0) + exit 1 + + scale = parse_scale(substr(units, 1, 1)) + if (scale < 0) + exit 1 + + printf "%d\n", size * base^scale + (size + 0 > 0 ? 0.5 : -0.5) + }' +} diff --git a/scripts/library/parse_options.sh b/scripts/library/parse_options.sh deleted file mode 100644 index 039eef92..00000000 --- a/scripts/library/parse_options.sh +++ /dev/null @@ -1,105 +0,0 @@ -# getopt like parser -parse_options() { - local short_options=$1; shift; - local long_options=$1; shift; - local ret=0; - local unused_options="" - local i - - while [[ -n $1 ]]; do - if [[ ${1:0:2} = '--' ]]; then - if [[ -n ${1:2} ]]; then - local match="" - for i in ${long_options//,/ }; do - if [[ ${1:2} = ${i//:} ]]; then - match=$i - break - fi - done - if [[ -n $match ]]; then - local needsargument=0 - - [[ ${match} = ${1:2}: ]] && needsargument=1 - [[ ${match} = ${1:2}:: && -n $2 && ${2:0:1} != "-" ]] && needsargument=1 - - if (( ! needsargument )); then - printf ' %s' "$1" - else - if [[ -n $2 ]]; then - printf ' %s ' "$1" - shift - printf "'%q" "$1" - while [[ -n $2 && ${2:0:1} != "-" ]]; do - shift - printf " %q" "$1" - done - printf "'" - else - printf "@SCRIPTNAME@: $(gettext "option %s requires an argument\n")" "'$1'" >&2 - ret=1 - fi - fi - else - echo "@SCRIPTNAME@: $(gettext "unrecognized option") '$1'" >&2 - ret=1 - fi - else - shift - break - fi - elif [[ ${1:0:1} = '-' ]]; then - for ((i=1; i<${#1}; i++)); do - if [[ $short_options =~ ${1:i:1} ]]; then - local needsargument=0 - - [[ $short_options =~ ${1:i:1}: && ! $short_options =~ ${1:i:1}:: ]] && needsargument=1 - [[ $short_options =~ ${1:i:1}:: && \ - ( -n ${1:$i+1} || ( -n $2 && ${2:0:1} != "-" ) ) ]] && needsargument=1 - - if (( ! needsargument )); then - printf ' -%s' "${1:i:1}" - else - if [[ -n ${1:$i+1} ]]; then - printf ' -%s ' "${1:i:1}" - printf "'%q" "${1:$i+1}" - while [[ -n $2 && ${2:0:1} != "-" ]]; do - shift - printf " %q" "$1" - done - printf "'" - else - if [[ -n $2 ]]; then - printf ' -%s ' "${1:i:1}" - shift - printf "'%q" "$1" - while [[ -n $2 && ${2:0:1} != "-" ]]; do - shift - printf " %q" "$1" - done - printf "'" - - else - printf "@SCRIPTNAME@: $(gettext "option %s requires an argument\n")" "'-${1:i:1}'" >&2 - ret=1 - fi - fi - break - fi - else - echo "@SCRIPTNAME@: $(gettext "unrecognized option") '-${1:i:1}'" >&2 - ret=1 - fi - done - else - unused_options="${unused_options} '$1'" - fi - shift - done - - printf " --" - [[ $unused_options ]] && printf ' %s' "${unused_options[@]}" - [[ $1 ]] && printf " '%s'" "$@" - printf "\n" - - return $ret -} diff --git a/scripts/library/parseopts.sh b/scripts/library/parseopts.sh new file mode 100644 index 00000000..11589ce3 --- /dev/null +++ b/scripts/library/parseopts.sh @@ -0,0 +1,141 @@ +# getopt-like parser +parseopts() { + local opt= optarg= i= shortopts=$1 + local -a longopts=() unused_argv=() + + shift + while [[ $1 && $1 != '--' ]]; do + longopts+=("$1") + shift + done + shift + + longoptmatch() { + local o longmatch=() + for o in "${longopts[@]}"; do + if [[ ${o%:} = "$1" ]]; then + longmatch=("$o") + break + fi + [[ ${o%:} = "$1"* ]] && longmatch+=("$o") + done + + case ${#longmatch[*]} in + 1) + # success, override with opt and return arg req (0 == none, 1 == required) + opt=${longmatch%:} + if [[ $longmatch = *: ]]; then + return 1 + else + return 0 + fi ;; + 0) + # fail, no match found + return 255 ;; + *) + # fail, ambiguous match + printf "@SCRIPTNAME@: $(gettext "option '%s' is ambiguous; possibilities:")" "--$1" + printf " '%s'" "${longmatch[@]%:}" + printf '\n' + return 254 ;; + esac >&2 + } + + while (( $# )); do + case $1 in + --) # explicit end of options + shift + break + ;; + -[!-]*) # short option + for (( i = 1; i < ${#1}; i++ )); do + opt=${1:i:1} + + # option doesn't exist + if [[ $shortopts != *$opt* ]]; then + printf "@SCRIPTNAME@: $(gettext "invalid option") -- '%s'\n" "$opt" >&2 + OPTRET=(--) + return 1 + fi + + OPTRET+=("-$opt") + # option requires optarg + if [[ $shortopts = *$opt:* ]]; then + # if we're not at the end of the option chunk, the rest is the optarg + if (( i < ${#1} - 1 )); then + OPTRET+=("${1:i+1}") + break + # if we're at the end, grab the the next positional, if it exists + elif (( i == ${#1} - 1 )) && [[ $2 ]]; then + OPTRET+=("$2") + shift + break + # parse failure + else + printf "@SCRIPTNAME@: $(gettext "option requires an argument") -- '%s'\n" "$opt" >&2 + OPTRET=(--) + return 1 + fi + fi + done + ;; + --?*=*|--?*) # long option + IFS='=' read -r opt optarg <<< "${1#--}" + longoptmatch "$opt" + case $? in + 0) + # parse failure + if [[ $optarg ]]; then + printf "@SCRIPTNAME@: $(gettext "option '%s' does not allow an argument")\n" "--$opt" >&2 + OPTRET=(--) + return 1 + # --longopt + else + OPTRET+=("--$opt") + shift + continue 2 + fi + ;; + 1) + # --longopt=optarg + if [[ $optarg ]]; then + OPTRET+=("--$opt" "$optarg") + shift + # --longopt optarg + elif [[ $2 ]]; then + OPTRET+=("--$opt" "$2" ) + shift 2 + # parse failure + else + printf "@SCRIPTNAME@: $(gettext "option '%s' requires an argument")\n" "--$opt" >&2 + OPTRET=(--) + return 1 + fi + continue 2 + ;; + 254) + # ambiguous option -- error was reported for us by longoptmatch() + OPTRET=(--) + return 1 + ;; + 255) + # parse failure + printf "@SCRIPTNAME@: $(gettext "invalid option") '--%s'\n" "$opt" >&2 + OPTRET=(--) + return 1 + ;; + esac + ;; + *) # non-option arg encountered, add it as a parameter + unused_argv+=("$1") + ;; + esac + shift + done + + # add end-of-opt terminator and any leftover positional parameters + OPTRET+=('--' "${unused_argv[@]}" "$@") + unset longoptmatch + + return 0 +} diff --git a/scripts/library/size_to_human.sh b/scripts/library/size_to_human.sh new file mode 100644 index 00000000..1d13eeb4 --- /dev/null +++ b/scripts/library/size_to_human.sh @@ -0,0 +1,22 @@ +size_to_human() { + awk -v size="$1" ' + BEGIN { + suffix[1] = "B" + suffix[2] = "KiB" + suffix[3] = "MiB" + suffix[4] = "GiB" + suffix[5] = "TiB" + suffix[6] = "PiB" + suffix[7] = "EiB" + count = 1 + + while (size > 1024) { + size /= 1024 + count++ + } + + sizestr = sprintf("%.2f", size) + sub(/\.?0+$/, "", sizestr) + printf("%s %s", sizestr, suffix[count]) + }' +} diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index e21418a6..b30e9d04 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -1,4 +1,4 @@ -#!/bin/bash -e +#!/bin/bash # # makepkg - make packages compatible for use with pacman # @configure_input@ @@ -39,19 +39,20 @@ export COMMAND_MODE='legacy' # Ensure CDPATH doesn't screw with our cd calls unset CDPATH -myver='@PACKAGE_VERSION@' -confdir='@sysconfdir@' -BUILDSCRIPT='@BUILDSCRIPT@' -startdir="$PWD" +declare -r myver='@PACKAGE_VERSION@' +declare -r confdir='@sysconfdir@' +declare -r BUILDSCRIPT='@BUILDSCRIPT@' +declare -r startdir="$PWD" packaging_options=('strip' 'docs' 'libtool' 'emptydirs' 'zipman' 'purge' 'upx') other_options=('ccache' 'distcc' 'buildflags' 'makeflags') -splitpkg_overrides=('pkgver' 'pkgrel' 'epoch' 'pkgdesc' 'arch' 'license' \ +splitpkg_overrides=('pkgver' 'pkgrel' 'epoch' 'pkgdesc' 'arch' 'url' 'license' \ 'groups' 'depends' 'optdepends' 'provides' 'conflicts' \ 'replaces' 'backup' 'options' 'install' 'changelog') readonly -a packaging_options other_options splitpkg_overrides # Options +ASDEPS=0 ASROOT=0 CLEANUP=0 DEP_BIN=0 @@ -70,6 +71,7 @@ LOGGING=0 SOURCEONLY=0 IGNOREARCH=0 HOLDVER=0 +PREPAREFUNC=0 BUILDFUNC=0 CHECKFUNC=0 PKGFUNC=0 @@ -168,7 +170,7 @@ clean_up() { # clean up dangling symlinks to packages for pkg in ${pkgname[@]}; do - for file in ${pkg}-*-*-${CARCH}{${PKGEXT},${SRCEXT}}; do + for file in ${pkg}-*-*-*{${PKGEXT},${SRCEXT}}; do if [[ -h $file && ! -e $file ]]; then rm -f "$file" fi @@ -211,7 +213,7 @@ get_filepath() { return 1 fi - echo "$file" + printf "%s\n" "$file" } # Print 'source not found' error message and exit makepkg @@ -226,13 +228,13 @@ get_filename() { # if a filename is specified, use it local filename="${1%%::*}" # if it is just an URL, we only keep the last component - echo "${filename##*/}" + printf "%s\n" "${filename##*/}" } # extract the URL from a source entry get_url() { # strip an eventual filename - echo "${1#*::}" + printf "%s\n" "${1#*::}" } ## @@ -242,9 +244,9 @@ get_url() { get_full_version() { if [[ -z $1 ]]; then if [[ $epoch ]] && (( ! $epoch )); then - echo $pkgver-$pkgrel + printf "%s\n" "$pkgver-$pkgrel" else - echo $epoch:$pkgver-$pkgrel + printf "%s\n" "$epoch:$pkgver-$pkgrel" fi else for i in pkgver pkgrel epoch; do @@ -253,9 +255,32 @@ get_full_version() { [[ -z ${!indirect} ]] && eval ${indirect}=\"${!i}\" done if (( ! $epoch_override )); then - echo $pkgver_override-$pkgrel_override + printf "%s\n" "$pkgver_override-$pkgrel_override" else - echo $epoch_override:$pkgver_override-$pkgrel_override + printf "%s\n" "$epoch_override:$pkgver_override-$pkgrel_override" + fi + fi +} + +## +# usage : get_pkg_arch( [$pkgname] ) +# return : architecture of the package +## +get_pkg_arch() { + if [[ -z $1 ]]; then + if [[ $arch = "any" ]]; then + printf "%s\n" "any" + else + printf "%s\n" "$CARCH" + fi + else + local arch_override + eval $(declare -f package_$1 | sed -n 's/\(^[[:space:]]*arch=\)/arch_override=/p') + (( ${#arch_override[@]} == 0 )) && arch_override=("${arch[@]}") + if [[ $arch_override = "any" ]]; then + printf "%s\n" "any" + else + printf "%s\n" "$CARCH" fi fi } @@ -264,63 +289,84 @@ get_full_version() { # Checks to see if options are present in makepkg.conf or PKGBUILD; # PKGBUILD options always take precedence. # -# usage : check_option( $option ) -# return : y - enabled -# n - disabled -# ? - not found +# usage : check_option( $option, $expected_val ) +# return : 0 - matches expected +# 1 - does not match expected +# 127 - not found ## check_option() { - local ret=$(in_opt_array "$1" ${options[@]}) - if [[ $ret != '?' ]]; then - echo $ret - return - fi + in_opt_array "$1" ${options[@]} + case $? in + 0) # assert enabled + [[ $2 = y ]] + return ;; + 1) # assert disabled + [[ $2 = n ]] + return + esac # fall back to makepkg.conf options - ret=$(in_opt_array "$1" ${OPTIONS[@]}) - if [[ $ret != '?' ]]; then - echo $ret - return - fi + in_opt_array "$1" ${OPTIONS[@]} + case $? in + 0) # assert enabled + [[ $2 = y ]] + return ;; + 1) # assert disabled + [[ $2 = n ]] + return + esac - echo '?' # Not Found + # not found + return 127 } ## # Check if option is present in BUILDENV # -# usage : check_buildenv( $option ) -# return : y - enabled -# n - disabled -# ? - not found +# usage : check_buildenv( $option, $expected_val ) +# return : 0 - matches expected +# 1 - does not match expected +# 127 - not found ## check_buildenv() { in_opt_array "$1" ${BUILDENV[@]} + case $? in + 0) # assert enabled + [[ $2 = "y" ]] + return ;; + 1) # assert disabled + [[ $2 = "n" ]] + return ;; + esac + + # not found + return 127 } ## # usage : in_opt_array( $needle, $haystack ) -# return : y - enabled -# n - disabled -# ? - not found +# return : 0 - enabled +# 1 - disabled +# 127 - not found ## in_opt_array() { local needle=$1; shift local opt for opt in "$@"; do - if [[ $opt = $needle ]]; then - echo 'y' # Enabled - return + if [[ $opt = "$needle" ]]; then + # enabled + return 0 elif [[ $opt = "!$needle" ]]; then - echo 'n' # Disabled - return + # disabled + return 1 fi done - echo '?' # Not Found + # not found + return 127 } @@ -333,15 +379,15 @@ in_array() { local needle=$1; shift local item for item in "$@"; do - [[ $item = $needle ]] && return 0 # Found + [[ $item = "$needle" ]] && return 0 # Found done return 1 # Not Found } -source_has_signatures(){ +source_has_signatures() { local file for file in "${source[@]}"; do - if [[ $file = *.@(sig?(n)|asc) ]]; then + if [[ ${file%%::*} = *.@(sig?(n)|asc) ]]; then return 0 fi done @@ -357,7 +403,7 @@ get_downloadclient() { local i for i in "${DLAGENTS[@]}"; do local handler="${i%%::*}" - if [[ $proto = $handler ]]; then + if [[ $proto = "$handler" ]]; then local agent="${i##*::}" break fi @@ -379,7 +425,7 @@ get_downloadclient() { exit 1 # $E_MISSING_PROGRAM fi - echo "$agent" + printf "%s\n" "$agent" } download_file() { @@ -420,33 +466,30 @@ download_file() { run_pacman() { local cmd if [[ ! $1 = -@(T|Qq) ]]; then - printf -v cmd "%q " "$PACMAN" $PACMAN_OPTS "$@" + cmd=("$PACMAN" $PACMAN_OPTS "$@") else - printf -v cmd "%q " "$PACMAN" "$@" + cmd=("$PACMAN" "$@") fi if (( ! ASROOT )) && [[ ! $1 = -@(T|Qq) ]]; then if type -p sudo >/dev/null; then - cmd="sudo $cmd" + cmd=(sudo "${cmd[@]}") else - cmd="su root -c '$cmd'" + cmd=(su root -c "$(printf '%q ' "${cmd[@]}")") fi fi - eval "$cmd" + "${cmd[@]}" } check_deps() { (( $# > 0 )) || return 0 - # Disable error trap in pacman subshell call as this breaks bash-3.2 compatibility - # Also, a non-zero return value is not unexpected and we are manually dealing them - set +E local ret=0 local pmout - pmout=$(run_pacman -T "$@") || ret=$? - set -E + pmout=$(run_pacman -T "$@") + ret=$? if (( ret == 127 )); then #unresolved deps - echo "$pmout" + printf "%s\n" "$pmout" elif (( ret )); then error "$(gettext "'%s' returned a fatal error (%i): %s")" "$PACMAN" "$ret" "$pmout" return "$ret" @@ -476,13 +519,11 @@ handle_deps() { fi # we might need the new system environment - # avoid triggering the ERR trap and exiting - set +e - local restoretrap=$(trap -p ERR) - trap - ERR + # save our shell options and turn off extglob + local shellopts=$(shopt -p) + shopt -u extglob source /etc/profile &>/dev/null - eval $restoretrap - set -e + eval "$shellopts" return $R_DEPS_SATISFIED } @@ -557,7 +598,7 @@ download_sources() { local url=$(get_url "$netfile") # if we get here, check to make sure it was a URL, else fail - if [[ $file = $url ]]; then + if [[ $file = "$url" ]]; then error "$(gettext "%s was not found in the build directory and is not a URL.")" "$file" exit 1 # $E_MISSING_FILE fi @@ -594,9 +635,9 @@ get_integlist() { done if (( ${#integlist[@]} > 0 )); then - echo ${integlist[@]} + printf "%s\n" "${integlist[@]}" else - echo ${INTEGRITY_CHECK[@]} + printf "%s\n" "${INTEGRITY_CHECK[@]}" fi } @@ -626,7 +667,7 @@ generate_checksums() { local ct=0 local numsrc=${#source[@]} - echo -n "${integ}sums=(" + printf "%s" "${integ}sums=(" local i local indent='' @@ -640,8 +681,8 @@ generate_checksums() { file="$(get_filepath "$netfile")" || missing_source_file "$netfile" local sum="$(openssl dgst -${integ} "$file")" sum=${sum##* } - (( ct )) && echo -n "$indent" - echo -n "'$sum'" + (( ct )) && printf "%s" "$indent" + printf "%s" "'$sum'" ct=$(($ct+1)) (( $ct < $numsrc )) && echo done @@ -667,7 +708,7 @@ check_checksums() { for file in "${source[@]}"; do local found=1 file="$(get_filename "$file")" - echo -n " $file ... " >&2 + printf "%s" " $file ... " >&2 if ! file="$(get_filepath "$file")"; then printf -- "$(gettext "NOT FOUND")\n" >&2 @@ -676,14 +717,18 @@ check_checksums() { fi if (( $found )) ; then - local expectedsum=$(tr '[:upper:]' '[:lower:]' <<< "${integrity_sums[$idx]}") - local realsum="$(openssl dgst -${integ} "$file")" - realsum="${realsum##* }" - if [[ $expectedsum = $realsum ]]; then - printf -- "$(gettext "Passed")\n" >&2 + if [[ ${integrity_sums[$idx]} = 'SKIP' ]]; then + echo "$(gettext "Skipped")" >&2 else - printf -- "$(gettext "FAILED")\n" >&2 - errors=1 + local expectedsum=$(tr '[:upper:]' '[:lower:]' <<< "${integrity_sums[$idx]}") + local realsum="$(openssl dgst -${integ} "$file")" + realsum="${realsum##* }" + if [[ $expectedsum = "$realsum" ]]; then + printf -- "$(gettext "Passed")\n" >&2 + else + printf -- "$(gettext "FAILED")\n" >&2 + errors=1 + fi fi fi @@ -837,10 +882,10 @@ extract_sources() { local ret=0 msg2 "$(gettext "Extracting %s with %s")" "$file" "$cmd" - if [[ $cmd = bsdtar ]]; then + if [[ $cmd = "bsdtar" ]]; then $cmd -xf "$file" || ret=$? else - rm -f "${file%.*}" + rm -f -- "${file%.*}" $cmd -dcf "$file" > "${file%.*}" || ret=$? fi if (( ret )); then @@ -869,6 +914,40 @@ error_function() { exit 2 # $E_BUILD_FAILED } +cd_safe() { + if ! cd "$1"; then + error "$(gettext "Failed to change to directory %s")" "$1" + plain "$(gettext "Aborting...")" + exit 1 + fi +} + +source_safe() { + shopt -u extglob + if ! source "$@"; then + error "$(gettext "Failed to source %s")" "$1" + exit 1 + fi + shopt -s extglob +} + +run_function_safe() { + local restoretrap + + set -e + set -E + + restoretrap=$(trap -p ERR) + trap 'error_function $pkgfunc' ERR + + run_function "$1" + + eval $restoretrap + + set +E + set +e +} + run_function() { if [[ -z $1 ]]; then return 1 @@ -876,25 +955,24 @@ run_function() { local pkgfunc="$1" # clear user-specified buildflags if requested - if [[ $(check_option buildflags) = "n" ]]; then - unset CFLAGS CXXFLAGS LDFLAGS + if check_option "buildflags" "n"; then + unset CPPFLAGS CFLAGS CXXFLAGS LDFLAGS fi # clear user-specified makeflags if requested - if [[ $(check_option makeflags) = "n" ]]; then + if check_option "makeflags" "n"; then unset MAKEFLAGS fi msg "$(gettext "Starting %s()...")" "$pkgfunc" - cd "$srcdir" + cd_safe "$srcdir" # ensure all necessary build variables are exported - export CFLAGS CXXFLAGS LDFLAGS MAKEFLAGS CHOST + export CPPFLAGS CFLAGS CXXFLAGS LDFLAGS MAKEFLAGS CHOST # save our shell options so pkgfunc() can't override what we need local shellopts=$(shopt -p) local ret=0 - local restoretrap if (( LOGGING )); then local fullver=$(get_full_version) local BUILDLOG="${startdir}/${pkgbase}-${fullver}-${CARCH}-$pkgfunc.log" @@ -916,40 +994,38 @@ run_function() { tee "$BUILDLOG" < "$logpipe" & local teepid=$! - restoretrap=$(trap -p ERR) - trap 'error_function $pkgfunc' ERR $pkgfunc &>"$logpipe" - eval $restoretrap wait $teepid rm "$logpipe" else - restoretrap=$(trap -p ERR) - trap 'error_function $pkgfunc' ERR $pkgfunc 2>&1 - eval $restoretrap fi # reset our shell options eval "$shellopts" } +run_prepare() { + run_function_safe "prepare" +} + run_build() { # use distcc if it is requested (check buildenv and PKGBUILD opts) - if [[ $(check_buildenv distcc) = "y" && $(check_option distcc) != "n" ]]; then + if check_buildenv "distcc" "y" && ! check_option "distc" "n"; then [[ -d /usr/lib/distcc/bin ]] && export PATH="/usr/lib/distcc/bin:$PATH" export DISTCC_HOSTS fi # use ccache if it is requested (check buildenv and PKGBUILD opts) - if [[ $(check_buildenv ccache) = "y" && $(check_option ccache) != "n" ]]; then + if check_buildenv "ccache" "y" && ! check_option "ccache" "n"; then [[ -d /usr/lib/ccache/bin ]] && export PATH="/usr/lib/ccache/bin:$PATH" fi - run_function "build" + run_function_safe "build" } run_check() { - run_function "check" + run_function_safe "check" } run_package() { @@ -960,73 +1036,65 @@ run_package() { pkgfunc="package_$1" fi - run_function "$pkgfunc" + run_function_safe "$pkgfunc" } tidy_install() { - cd "$pkgdir" + cd_safe "$pkgdir" msg "$(gettext "Tidying install...")" - if [[ $(check_option docs) = "n" && -n ${DOC_DIRS[*]} ]]; then + if check_option "docs" "n" && [[ -n ${DOC_DIRS[*]} ]]; then msg2 "$(gettext "Removing doc files...")" - rm -rf ${DOC_DIRS[@]} + rm -rf -- ${DOC_DIRS[@]} fi - if [[ $(check_option purge) = "y" && -n ${PURGE_TARGETS[*]} ]]; then + if check_option "purge" "y" && [[ -n ${PURGE_TARGETS[*]} ]]; then msg2 "$(gettext "Purging unwanted files...")" local pt for pt in "${PURGE_TARGETS[@]}"; do - if [[ ${pt} = ${pt//\/} ]]; then - find . -type f -name "${pt}" -exec rm -f -- '{}' \; + if [[ ${pt} = "${pt//\/}" ]]; then + find . ! -type d -name "${pt}" -exec rm -f -- '{}' \; else rm -f ${pt} fi done fi - if [[ $(check_option zipman) = "y" && -n ${MAN_DIRS[*]} ]]; then + if check_option "zipman" "y" && [[ -n ${MAN_DIRS[*]} ]]; then msg2 "$(gettext "Compressing man and info pages...")" - local manpage ext file link hardlinks hl - find ${MAN_DIRS[@]} -type f 2>/dev/null | - while read manpage ; do - ext="${manpage##*.}" - file="${manpage##*/}" - if [[ $ext != gz && $ext != bz2 ]]; then - # update symlinks to this manpage - find ${MAN_DIRS[@]} -lname "$file" 2>/dev/null | - while read link ; do + local file files inode link + while read -rd ' ' inode; do + read file + find ${MAN_DIRS[@]} -type l 2>/dev/null | + while read link ; do + if [[ "${file}" -ef "${link}" ]] ; then rm -f "$link" "${link}.gz" - ln -s "${file}.gz" "${link}.gz" - done - - # check file still exists (potentially already compressed due to hardlink) - if [[ -f ${manpage} ]]; then - # find hard links and remove them - # the '|| true' part keeps the script from bailing on the EOF returned - # by read at the end of the find output - IFS=$'\n' read -rd '' -a hardlinks < \ - <(find ${MAN_DIRS[@]} \! -name "$file" -samefile "$manpage" \ - 2>/dev/null || true) || true - rm -f "${hardlinks[@]}" - # 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 [[ ${file%/*} = ${link%/*} ]]; then + ln -s -- "${file##*/}.gz" "${link}.gz" + else + ln -s -- "/${file}.gz" "${link}.gz" + fi fi + done + if [[ -z ${files[$inode]} ]]; then + files[$inode]=$file + gzip -9 -f "$file" + else + rm -f "$file" + ln "${files[$inode]}.gz" "${file}.gz" + chmod 644 "${file}.gz" fi - done + done < <(find ${MAN_DIRS[@]} -type f \! -name "*.gz" \! -name "*.bz2" \ + -exec @INODECMD@ '{}' + 2>/dev/null) fi - if [[ $(check_option strip) = y ]]; then + if check_option "strip" "y"; then msg2 "$(gettext "Stripping unneeded symbols from binaries and libraries...")" # make sure library stripping variables are defined to prevent excess stripping [[ -z ${STRIP_SHARED+x} ]] && STRIP_SHARED="-S" [[ -z ${STRIP_STATIC+x} ]] && STRIP_STATIC="-S" local binary - find . -type f -perm -u+w 2>/dev/null | while read binary ; do + find . -type f -perm -u+w -print0 2>/dev/null | while read -d '' binary ; do case "$(file -bi "$binary")" in *application/x-sharedlib*) # Libraries (.so) strip $STRIP_SHARED "$binary";; @@ -1038,17 +1106,17 @@ tidy_install() { done fi - if [[ $(check_option libtool) = "n" ]]; then + if check_option "libtool" "n"; then msg2 "$(gettext "Removing "%s" files...")" "libtool" find . ! -type d -name "*.la" -exec rm -f -- '{}' \; fi - if [[ $(check_option emptydirs) = "n" ]]; then + if check_option "emptydirs" "n"; then msg2 "$(gettext "Removing empty directories...")" - find . -depth -type d -empty -delete + find . -depth -type d -exec rmdir '{}' + 2>/dev/null fi - if [[ $(check_option upx) = "y" ]]; then + if check_option "upx" "y"; then msg2 "$(gettext "Compressing binaries with %s...")" "UPX" local binary find . -type f -perm -u+w 2>/dev/null | while read binary ; do @@ -1061,12 +1129,29 @@ tidy_install() { } find_libdepends() { - local libdepends - find "$pkgdir" -type f -perm -u+x | while read filename - do + local d sodepends; + + sodepends=0; + for d in "${depends[@]}"; do + if [[ $d = *.so ]]; then + sodepends=1; + break; + fi + done + + if (( sodepends == 0 )); then + printf '%s\n' "${depends[@]}" + return; + fi + + local libdeps filename soarch sofile soname soversion; + declare -A libdeps; + + while read filename; do # get architecture of the file; if soarch is empty it's not an ELF binary soarch=$(LC_ALL=C readelf -h "$filename" 2>/dev/null | sed -n 's/.*Class.*ELF\(32\|64\)/\1/p') - [ -n "$soarch" ] || continue + [[ -n "$soarch" ]] || continue + # process all libraries needed by the binary for sofile in $(LC_ALL=C readelf -d "$filename" 2>/dev/null | sed -nr 's/.*Shared library: \[(.*)\].*/\1/p') do @@ -1074,42 +1159,97 @@ find_libdepends() { soname="${sofile%.so?(+(.+([0-9])))}".so # extract the major version: 1 soversion="${sofile##*\.so\.}" - if in_array "${soname}" ${depends[@]}; then - if ! in_array "${soname}=${soversion}-${soarch}" ${libdepends[@]}; then - # libfoo.so=1-64 - echo "${soname}=${soversion}-${soarch}" - libdepends=(${libdepends[@]} "${soname}=${soversion}-${soarch}") + + if [[ ${libdeps[$soname]} ]]; then + if [[ ${libdeps[$soname]} != *${soversion}-${soarch}* ]]; then + libdeps[$soname]+=" ${soversion}-${soarch}" fi + else + libdeps[$soname]="${soversion}-${soarch}" fi done + done < <(find "$pkgdir" -type f -perm -u+x) + + local libdepends v + for d in "${depends[@]}"; do + case "$d" in + *.so) + if [[ ${libdeps[$d]} ]]; then + for v in ${libdeps[$d]}; do + libdepends+=("$d=$v") + done + else + warning "$(gettext "Library listed in %s is not required by any files: %s")" "'depends'" "$d" + libdepends+=("$d") + fi + ;; + *) + libdepends+=("$d") + ;; + esac done + + printf '%s\n' "${libdepends[@]}" } -find_libprovides() { - local libprovides - find "$pkgdir" -type f -name \*.so\* | while read filename - do - # check if we really have a shared object - if LC_ALL=C readelf -h "$filename" 2>/dev/null | grep -q '.*Type:.*DYN (Shared object file).*'; then - # 64 - soarch=$(LC_ALL=C readelf -h "$filename" | sed -n 's/.*Class.*ELF\(32\|64\)/\1/p') - # get the string binaries link to: libfoo.so.1.2 -> libfoo.so.1 - sofile=$(LC_ALL=C readelf -d "$filename" 2>/dev/null | sed -n 's/.*Library soname: \[\(.*\)\].*/\1/p') - [ -z "$sofile" ] && sofile="${filename##*/}" - # extract the library name: libfoo.so - soname="${sofile%%\.so\.*}.so" - # extract the major version: 1 - soversion="${sofile##*\.so\.}" - if in_array "${soname}" ${provides[@]}; then - if ! in_array "${soname}=${soversion}-${soarch}" ${libprovides[@]}; then - # libfoo.so=1-64 - echo "${soname}=${soversion}-${soarch}" - libprovides=(${libprovides[@]} "${soname}=${soversion}-${soarch}") +find_libprovides() { + local p libprovides missing + for p in "${provides[@]}"; do + missing=0 + case "$p" in + *.so) + mapfile -t filename < <(find "$pkgdir" -type f -name $p\*) + if [[ $filename ]]; then + # packages may provide multiple versions of the same library + for fn in "${filename[@]}"; do + # check if we really have a shared object + if LC_ALL=C readelf -h "$fn" 2>/dev/null | grep -q '.*Type:.*DYN (Shared object file).*'; then + # get the string binaries link to (e.g. libfoo.so.1.2 -> libfoo.so.1) + local sofile=$(LC_ALL=C readelf -d "$fn" 2>/dev/null | sed -n 's/.*Library soname: \[\(.*\)\].*/\1/p') + if [[ -z "$sofile" ]]; then + warning "$(gettext "Library listed in %s is not versioned: %s")" "'provides'" "$p" + libprovides+=("$p") + continue + fi + + # get the library architecture (32 or 64 bit) + local soarch=$(LC_ALL=C readelf -h "$fn" | sed -n 's/.*Class.*ELF\(32\|64\)/\1/p') + + # extract the library major version + local soversion="${sofile##*\.so\.}" + + libprovides+=("${p}=${soversion}-${soarch}") + else + warning "$(gettext "Library listed in %s is not a shared object: %s")" "'provides'" "$p" + libprovides+=("$p") + fi + done + else + libprovides+=("$p") + missing=1 fi - fi - fi + ;; + *) + libprovides+=("$p") + ;; + esac + + if (( missing )); then + warning "$(gettext "Can not find library listed in %s: %s")" "'provides'" "$p" + fi done + + printf '%s\n' "${libprovides[@]}" +} + +check_license() { + # TODO maybe remove this at some point + # warn if license array is not present or empty + if [[ -z $license ]]; then + warning "$(gettext "Please add a license line to your %s!")" "$BUILDSCRIPT" + plain "$(gettext "Example for GPL\'ed software: %s.")" "license=('GPL')" + fi } write_pkginfo() { @@ -1134,79 +1274,48 @@ write_pkginfo() { echo "# using $(fakeroot -v)" fi echo "# $(LC_ALL=C date -u)" - echo "pkgname = $1" + printf "pkgname = %s\n" "$1" (( SPLITPKG )) && echo pkgbase = $pkgbase echo "pkgver = $(get_full_version)" - echo "pkgdesc = $pkgdesc" - echo "url = $url" - echo "builddate = $builddate" - echo "packager = $packager" - echo "size = $size" - echo "arch = $PKGARCH" - - [[ $license ]] && printf "license = %s\n" "${license[@]}" - [[ $replaces ]] && printf "replaces = %s\n" "${replaces[@]}" - [[ $groups ]] && printf "group = %s\n" "${groups[@]}" - [[ $optdepends ]] && printf "optdepend = %s\n" "${optdepends[@]//+([[:space:]])/ }" - [[ $conflicts ]] && printf "conflict = %s\n" "${conflicts[@]}" - [[ $backup ]] && printf "backup = %s\n" "${backup[@]}" + printf "pkgdesc = %s\n" "$pkgdesc" + printf "url = %s\n" "$url" + printf "builddate = %s\n" "$builddate" + printf "packager = %s\n" "$packager" + printf "size = %s\n" "$size" + printf "arch = %s\n" "$pkgarch" + + mapfile -t provides < <(find_libprovides) + mapfile -t depends < <(find_libdepends) + + [[ $license ]] && printf "license = %s\n" "${license[@]}" + [[ $replaces ]] && printf "replaces = %s\n" "${replaces[@]}" + [[ $groups ]] && printf "group = %s\n" "${groups[@]}" + [[ $conflicts ]] && printf "conflict = %s\n" "${conflicts[@]}" + [[ $provides ]] && printf "provides = %s\n" "${provides[@]}" + [[ $backup ]] && printf "backup = %s\n" "${backup[@]}" + [[ $depends ]] && printf "depend = %s\n" "${depends[@]}" + [[ $optdepends ]] && printf "optdepend = %s\n" "${optdepends[@]//+([[:space:]])/ }" + [[ $makedepends ]] && printf "makedepend = %s\n" "${makedepends[@]}" + [[ $checkdepends ]] && printf "checkdepend = %s\n" "${checkdepends[@]}" local it - - libprovides=$(find_libprovides) - libdepends=$(find_libdepends) - provides=("${provides[@]}" ${libprovides}) - depends=("${depends[@]}" ${libdepends}) - - for it in "${depends[@]}"; do - if [[ $it = *.so ]]; then - # check if the entry has been found by find_libdepends - # if not, it's unneeded; tell the user so he can remove it - printf -v re '(^|\s)%s=.*' "$it" - if [[ ! $libdepends =~ $re ]]; then - error "$(gettext "Cannot find library listed in %s: %s")" "'depends'" "$it" - return 1 - fi - else - echo "depend = $it" - fi - done - - for it in "${provides[@]}"; do - # ignore versionless entires (those come from the PKGBUILD) - if [[ $it = *.so ]]; then - # check if the entry has been found by find_libprovides - # if not, it's unneeded; tell the user so he can remove it - if [[ ! $libprovides =~ (^|\s)${it}=.* ]]; then - error "$(gettext "Cannot find library listed in %s: %s")" "'provides'" "$it" - return 1 - fi - else - echo "provides = $it" - fi - done - for it in "${packaging_options[@]}"; do - local ret="$(check_option $it)" - if [[ $ret != "?" ]]; then - if [[ $ret = y ]]; then - echo "makepkgopt = $it" - else - echo "makepkgopt = !$it" - fi - fi + check_option "$it" "y" + case $? in + 0) + printf "makepkgopt = %s\n" "$it" + ;; + 1) + printf "makepkgopt = %s\n" "!$it" + ;; + esac done - # TODO maybe remove this at some point - # warn if license array is not present or empty - if [[ -z $license ]]; then - warning "$(gettext "Please add a license line to your %s!")" "$BUILDSCRIPT" - plain "$(gettext "Example for GPL\'ed software: %s.")" "license=('GPL')" - fi + check_license } check_package() { - cd "$pkgdir" + cd_safe "$pkgdir" # check existence of backup files local file @@ -1235,7 +1344,7 @@ create_package() { check_package - cd "$pkgdir" + cd_safe "$pkgdir" msg "$(gettext "Creating package...")" local nameofpkg @@ -1245,15 +1354,11 @@ create_package() { nameofpkg="$1" fi - if [[ $arch = "any" ]]; then - PKGARCH="any" - else - PKGARCH=$CARCH - fi + pkgarch=$(get_pkg_arch) write_pkginfo $nameofpkg > .PKGINFO - local comp_files=".PKGINFO" + local comp_files=('.PKGINFO') # check for changelog/install files for i in 'changelog/.CHANGELOG' 'install/.INSTALL'; do @@ -1263,7 +1368,7 @@ create_package() { msg2 "$(gettext "Adding %s file...")" "$orig" cp "$startdir/${!orig}" "$dest" chmod 644 "$dest" - comp_files+=" $dest" + comp_files+=("$dest") fi done @@ -1271,7 +1376,7 @@ create_package() { msg2 "$(gettext "Compressing package...")" local fullver=$(get_full_version) - local pkg_file="$PKGDEST/${nameofpkg}-${fullver}-${PKGARCH}${PKGEXT}" + local pkg_file="$PKGDEST/${nameofpkg}-${fullver}-${pkgarch}${PKGEXT}" local ret=0 [[ -f $pkg_file ]] && rm -f "$pkg_file" @@ -1285,12 +1390,12 @@ create_package() { # bsdtar's gzip compression always saves the time stamp, making one # archive created using the same command line distinct from another. # Disable bsdtar compression and use gzip -n for now. - bsdtar -cf - $comp_files * | + bsdtar -cf - "${comp_files[@]}" * | case "$PKGEXT" in - *tar.gz) gzip -c -f -n ;; - *tar.bz2) bzip2 -c -f ;; - *tar.xz) xz -c -z - ;; - *tar.Z) compress -c -f ;; + *tar.gz) ${COMPRESSGZ[@]:-gzip -c -f -n} ;; + *tar.bz2) ${COMPRESSBZ2[@]:-bzip2 -c -f} ;; + *tar.xz) ${COMPRESSXZ[@]:-xz -c -z -} ;; + *tar.Z) ${COMPRESSZ[@]:-compress -c -f} ;; *tar) cat ;; *) warning "$(gettext "'%s' is not a valid archive extension.")" \ "$PKGEXT"; cat ;; @@ -1350,12 +1455,14 @@ create_srcpackage() { local srclinks="$(mktemp -d "$startdir"/srclinks.XXXXXXXXX)" mkdir "${srclinks}"/${pkgbase} + check_license + msg2 "$(gettext "Adding %s...")" "$BUILDSCRIPT" ln -s "${BUILDFILE}" "${srclinks}/${pkgbase}/${BUILDSCRIPT}" local file for file in "${source[@]}"; do - if [[ "$file" == $(get_filename "$file") ]] || (( SOURCEONLY == 2 )); then + if [[ "$file" = "$(get_filename "$file")" ]] || (( SOURCEONLY == 2 )); then local absfile absfile=$(get_filepath "$file") || missing_source_file "$file" msg2 "$(gettext "Adding %s...")" "${absfile##*/}" @@ -1392,7 +1499,7 @@ create_srcpackage() { # tar it up msg2 "$(gettext "Compressing source package...")" - cd "${srclinks}" + cd_safe "${srclinks}" if ! bsdtar -c${TAR_OPT}Lf "$pkg_file" ${pkgbase}; then error "$(gettext "Failed to create source package file.")" exit 1 # TODO: error code @@ -1408,7 +1515,7 @@ create_srcpackage() { warning "$(gettext "Failed to create symlink to source package file.")" fi - cd "${startdir}" + cd_safe "${startdir}" rm -rf "${srclinks}" } @@ -1421,17 +1528,16 @@ install_package() { msg "$(gettext "Installing %s package group with %s...")" "$pkgbase" "$PACMAN -U" fi - local fullver pkg pkglist + local fullver pkgarch pkg pkglist + (( ASDEPS )) && pkglist+=('--asdeps') + for pkg in ${pkgname[@]}; do fullver=$(get_full_version $pkg) - if [[ -f $PKGDEST/${pkg}-${fullver}-${CARCH}${PKGEXT} ]]; then - pkglist+=" $PKGDEST/${pkg}-${fullver}-${CARCH}${PKGEXT}" - else - pkglist+=" $PKGDEST/${pkg}-${fullver}-any${PKGEXT}" - fi + pkgarch=$(get_pkg_arch $pkg) + pkglist+=("$PKGDEST/${pkg}-${fullver}-${pkgarch}${PKGEXT}") done - if ! run_pacman -U $pkglist; then + if ! run_pacman -U ${pkglist[@]}; then warning "$(gettext "Failed to install built package(s).")" return 0 fi @@ -1477,8 +1583,8 @@ check_sanity() { awk -F'=' '$1 ~ /^[[:space:]]*pkgrel$/' "$BUILDFILE" | sed "s/[[:space:]]*#.*//" | while IFS='=' read -r _ i; do eval i=\"$(sed 's/^\(['\''"]\)\(.*\)\1$/\2/' <<< "${i%%+([[:space:]])}")\" - if [[ $i = *[[:space:]-]* ]]; then - error "$(gettext "%s is not allowed to contain hyphens or whitespace.")" "pkgrel" + if [[ $i != +([0-9])?(.+([0-9])) ]]; then + error "$(gettext "%s must be a decimal.")" "pkgrel" return 1 fi done || ret=1 @@ -1570,7 +1676,7 @@ check_sanity() { known=0 # check if option matches a known option or its inverse for kopt in ${packaging_options[@]} ${other_options[@]}; do - if [[ ${i} = ${kopt} || ${i} = "!${kopt}" ]]; then + if [[ ${i} = "${kopt}" || ${i} = "!${kopt}" ]]; then known=1 fi done @@ -1609,12 +1715,12 @@ check_software() { # check for sudo if we will need it during makepkg execution if (( ! ( ASROOT || INFAKEROOT ) && ( DEP_BIN || RMDEPS || INSTALL ) )); then if ! type -p sudo >/dev/null; then - warning "$(gettext "Sudo can not be found. Will use su to acquire root privileges.")" + warning "$(gettext "Cannot find the %s binary. Will use %s to acquire root privileges.")" "sudo" "su" fi fi # fakeroot - building as non-root user - if [[ $(check_buildenv fakeroot) = "y" ]] && (( EUID > 0 )); then + if check_buildenv "fakeroot" "y" && (( EUID > 0 )); then if ! type -p fakeroot >/dev/null; then error "$(gettext "Cannot find the %s binary required for building as non-root user.")" "fakeroot" ret=1 @@ -1622,7 +1728,7 @@ check_software() { fi # gpg - package signing - if [[ $SIGNPKG == 'y' || (-z "$SIGNPKG" && $(check_buildenv sign) == 'y') ]]; then + if [[ $SIGNPKG == 'y' ]] || { [[ -z $SIGNPKG ]] && check_buildenv "sign" "y"; }; then if ! type -p gpg >/dev/null; then error "$(gettext "Cannot find the %s binary required for signing packages.")" "gpg" ret=1 @@ -1646,7 +1752,7 @@ check_software() { fi # upx - binary compression - if [[ $(check_option upx) == 'y' ]]; then + if check_option "upx" "y"; then if ! type -p upx >/dev/null; then error "$(gettext "Cannot find the %s binary required for compressing binaries.")" "upx" ret=1 @@ -1654,7 +1760,7 @@ check_software() { fi # distcc - compilation with distcc - if [[ $(check_buildenv distcc) = "y" && $(check_option distcc) != "n" ]]; then + if check_buildenv "distcc" "y" && ! check_option "distcc" "n" ]]; then if ! type -p distcc >/dev/null; then error "$(gettext "Cannot find the %s binary required for distributed compilation.")" "distcc" ret=1 @@ -1662,7 +1768,7 @@ check_software() { fi # ccache - compilation with ccache - if [[ $(check_buildenv ccache) = "y" && $(check_option ccache) != "n" ]]; then + if check_buildenv "ccache" "y" && ! check_option "ccache" "n"; then if ! type -p ccache >/dev/null; then error "$(gettext "Cannot find the %s binary required for compiler cache usage.")" "ccache" ret=1 @@ -1670,7 +1776,7 @@ check_software() { fi # strip - strip symbols from binaries/libraries - if [[ $(check_option strip) = "y" ]]; then + if check_option "strip" "y"; then if ! type -p strip >/dev/null; then error "$(gettext "Cannot find the %s binary required for object file stripping.")" "strip" ret=1 @@ -1678,7 +1784,7 @@ check_software() { fi # gzip - compressig man and info pages - if [[ $(check_option zipman) = "y" ]]; then + if check_option "zipman" "y"; then if ! type -p gzip >/dev/null; then error "$(gettext "Cannot find the %s binary required for compressing man and info pages.")" "gzip" ret=1 @@ -1694,7 +1800,7 @@ devel_check() { # Do not update pkgver if --holdver is set, when building a source package, repackaging, # reading PKGBUILD from pipe (-f), or if we cannot write to the file (-w) if (( HOLDVER || SOURCEONLY || REPKG )) || - [[ ! -f $BUILDFILE || ! -w $BUILDFILE || $BUILDFILE = /dev/stdin ]]; then + [[ ! -f $BUILDFILE || ! -w $BUILDFILE || $BUILDFILE = "/dev/stdin" ]]; then return fi @@ -1704,66 +1810,67 @@ devel_check() { # calls to makepkg via fakeroot will explicitly pass the version # number to avoid having to determine the version number twice. # Also do a check to make sure we have the VCS tool available. - oldpkgver=$pkgver - if [[ -n ${_darcstrunk} && -n ${_darcsmod} ]] ; then - if ! type -p darcs >/dev/null; then - warning "$(gettext "Cannot find the %s binary required to determine latest %s revision.")" "darcs" "darcs" - return 0 - fi - msg "$(gettext "Determining latest %s revision...")" 'darcs' - newpkgver=$(date +%Y%m%d) - elif [[ -n ${_cvsroot} && -n ${_cvsmod} ]] ; then - if ! type -p cvs >/dev/null; then - warning "$(gettext "Cannot find the %s binary required to determine latest %s revision.")" "cvs" "cvs" - return 0 - fi - msg "$(gettext "Determining latest %s revision...")" 'cvs' - newpkgver=$(date +%Y%m%d) - elif [[ -n ${_gitroot} && -n ${_gitname} ]] ; then - if ! type -p git >/dev/null; then - warning "$(gettext "Cannot find the %s binary required to determine latest %s revision.")" "git" "git" - return 0 - fi - msg "$(gettext "Determining latest %s revision...")" 'git' - newpkgver=$(date +%Y%m%d) - elif [[ -n ${_svntrunk} && -n ${_svnmod} ]] ; then - if ! type -p svn >/dev/null; then - warning "$(gettext "Cannot find the %s binary required to determine latest %s revision.")" "svn" "svn" - return 0 - fi - msg "$(gettext "Determining latest %s revision...")" 'svn' - newpkgver=$(LC_ALL=C svn info $_svntrunk | sed -n 's/^Last Changed Rev: \([0-9]*\)$/\1/p') - elif [[ -n ${_bzrtrunk} && -n ${_bzrmod} ]] ; then - if ! type -p bzr >/dev/null; then - warning "$(gettext "Cannot find the %s binary required to determine latest %s revision.")" "bzr" "bzr" - return 0 - fi - msg "$(gettext "Determining latest %s revision...")" 'bzr' - newpkgver=$(bzr revno ${_bzrtrunk}) - elif [[ -n ${_hgroot} && -n ${_hgrepo} ]] ; then - if ! type -p hg >/dev/null; then - warning "$(gettext "Cannot find the %s binary required to determine latest %s revision.")" "hg" "hg" - return 0 - fi - msg "$(gettext "Determining latest %s revision...")" 'hg' - if [[ -d ./src/$_hgrepo ]] ; then - cd ./src/$_hgrepo - local ret=0 - hg pull || ret=$? - if (( ! ret )); then - hg update - elif (( ret != 1 )); then - return 1 - fi - else - [[ ! -d ./src/ ]] && mkdir ./src/ - hg clone $_hgroot/$_hgrepo ./src/$_hgrepo - cd ./src/$_hgrepo - fi - newpkgver=$(hg tip --template "{rev}") - cd ../../ + local vcs=() + + [[ -n ${_darcstrunk} && -n ${_darcsmod} ]] && vcs+=("darcs") + [[ -n ${_cvsroot} && -n ${_cvsmod} ]] && vcs+=("cvs") + [[ -n ${_gitroot} && -n ${_gitname} ]] && vcs+=("git") + [[ -n ${_svntrunk} && -n ${_svnmod} ]] && vcs+=("svn") + [[ -n ${_bzrtrunk} && -n ${_bzrmod} ]] && vcs+=("bzr") + [[ -n ${_hgroot} && -n ${_hgrepo} ]] && vcs+=("hg") + + if (( ${#vcs[@]} == 0 )); then + return + elif (( ${#vcs[@]} > 1 )); then + warning "$(gettext "Ambiguous VCS package. Cannot pick from: %s.")" "${vcs[*]}" + return 0 + fi + + if ! type -p "$vcs" >/dev/null; then + warning "$(gettext "Cannot find the %s binary required to determine latest %s revision.")" "$vcs" "$vcs" + return 0 fi + msg "$(gettext "Determining latest %s revision...")" "$vcs" + + case "$vcs" in + darcs) + newpkgver=$(date +%Y%m%d) + ;; + cvs) + newpkgver=$(date +%Y%m%d) + ;; + git) + newpkgver=$(date +%Y%m%d) + ;; + svn) + newpkgver=$(LC_ALL=C svn info $_svntrunk | sed -n 's/^Last Changed Rev: \([0-9]*\)$/\1/p') + ;; + bzr) + newpkgver=$(bzr revno ${_bzrtrunk}) + ;; + hg) + if pushd "./src/$_hgrepo" > /dev/null; then + local ret=0 + hg pull || ret=$? + if (( ! ret )); then + hg update + elif (( ret != 1 )); then + return 1 + fi + else + [[ ! -d ./src/ ]] && mkdir ./src/ + hg clone "$_hgroot/$_hgrepo" "./src/$_hgrepo" + if ! pushd "./src/$_hgrepo" > /dev/null; then + warning "$(gettext "An error occured while determining the hg version number.")" + return 0 + fi + fi + newpkgver=$(hg tip --template "{rev}") + popd > /dev/null + ;; + esac + if [[ -n $newpkgver ]]; then msg2 "$(gettext "Version found: %s")" "$newpkgver" fi @@ -1784,13 +1891,13 @@ devel_update() { # ... # _foo=pkgver # - if [[ -n $newpkgver ]]; then - if [[ $newpkgver != "$pkgver" ]]; then - if [[ -f $BUILDFILE && -w $BUILDFILE ]]; then - @SEDINPLACE@ "s/^pkgver=[^ ]*/pkgver=$newpkgver/" "$BUILDFILE" - @SEDINPLACE@ "s/^pkgrel=[^ ]*/pkgrel=1/" "$BUILDFILE" - source "$BUILDFILE" - fi + if [[ -n $newpkgver && $newpkgver != "$pkgver" ]]; then + if [[ -f $BUILDFILE && -w $BUILDFILE ]]; then + @SEDINPLACE@ "s/^pkgver=[^ ]*/pkgver=$newpkgver/" "$BUILDFILE" + @SEDINPLACE@ "s/^pkgrel=[^ ]*/pkgrel=1/" "$BUILDFILE" + source "$BUILDFILE" + else + warning "$(gettext "%s is not writeable -- pkgver will not be updated")" "$BUILDFILE" fi fi } @@ -1837,15 +1944,15 @@ canonicalize_path() { if [[ -d $path ]]; then ( - cd "$path" + cd_safe "$path" pwd -P ) else - echo "$path" + printf "%s\n" "$path" fi } -m4_include(library/parse_options.sh) +m4_include(library/parseopts.sh) usage() { printf "makepkg (pacman) %s\n" "$myver" @@ -1886,6 +1993,7 @@ usage() { printf -- "$(gettext "These options can be passed to %s:")\n" "pacman" echo printf -- "$(gettext " --noconfirm Do not ask for confirmation when resolving dependencies")\n" + printf -- "$(gettext " --asdeps Install packages as non-explicitly installed")\n" printf -- "$(gettext " --noprogressbar Do not show a progress bar when downloading files")\n" echo printf -- "$(gettext "If %s is not specified, %s will look for '%s'")\n" "-p" "makepkg" "$BUILDSCRIPT" @@ -1906,7 +2014,7 @@ There is NO WARRANTY, to the extent permitted by law.\n")" # determine whether we have gettext; make it a no-op if we do not if ! type -p gettext >/dev/null; then gettext() { - echo "$@" + printf "%s\n" "$@" } fi @@ -1914,23 +2022,25 @@ ARGLIST=("$@") # Parse Command Line Options. OPT_SHORT="AcdefFghiLmop:rRsSV" -OPT_LONG="allsource,asroot,ignorearch,check,clean,nodeps" -OPT_LONG+=",noextract,force,forcever:,geninteg,help,holdver,skippgpcheck" -OPT_LONG+=",install,key:,log,nocolor,nobuild,nocheck,nosign,pkg:,rmdeps" -OPT_LONG+=",repackage,skipchecksums,skipinteg,skippgpcheck,sign,source,syncdeps" -OPT_LONG+=",version,config:" +OPT_LONG=('allsource' 'asroot' 'ignorearch' 'check' 'clean' 'nodeps' + 'noextract' 'force' 'forcever:' 'geninteg' 'help' 'holdver' 'skippgpcheck' + 'install' 'key:' 'log' 'nocolor' 'nobuild' 'nocheck' 'nosign' 'pkg:' 'rmdeps' + 'repackage' 'skipchecksums' 'skipinteg' 'skippgpcheck' 'sign' 'source' 'syncdeps' + 'version' 'config:') # Pacman Options -OPT_LONG+=",noconfirm,noprogressbar" -if ! OPT_TEMP="$(parse_options $OPT_SHORT $OPT_LONG "$@")"; then - echo; usage; exit 1 # E_INVALID_OPTION; +OPT_LONG+=('asdeps' 'noconfirm' 'noprogressbar') + +if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then + exit 1 # E_INVALID_OPTION; fi -eval set -- "$OPT_TEMP" -unset OPT_SHORT OPT_LONG OPT_TEMP +set -- "${OPTRET[@]}" +unset OPT_SHORT OPT_LONG OPTRET while true; do case "$1" in # Pacman Options + --asdeps) ASDEPS=1;; --noconfirm) PACMAN_OPTS+=" --noconfirm" ;; --noprogressbar) PACMAN_OPTS+=" --noprogressbar" ;; @@ -1957,7 +2067,7 @@ while true; do --nosign) SIGNPKG='n' ;; -o|--nobuild) NOBUILD=1 ;; -p) shift; BUILDFILE=$1 ;; - --pkg) shift; PKGLIST=($1) ;; + --pkg) shift; IFS=, read -ra p <<<"$1"; PKGLIST+=("${p[@]}"); unset p ;; -r|--rmdeps) RMDEPS=1 ;; -R|--repackage) REPKG=1 ;; --skipchecksums) SKIPCHECKSUMS=1 ;; @@ -1970,8 +2080,7 @@ while true; do -h|--help) usage; exit 0 ;; # E_OK -V|--version) version; exit 0 ;; # E_OK - --) OPT_IND=0; shift; break;; - *) usage; exit 1 ;; # E_INVALID_OPTION + --) OPT_IND=0; shift; break 2;; esac shift done @@ -1983,7 +2092,6 @@ for signal in TERM HUP QUIT; do done trap 'trap_exit INT "$(gettext "Aborted by user! Exiting...")"' INT trap 'trap_exit USR1 "$(gettext "An unknown error has occurred. Exiting...")"' ERR -set -E # preserve environment variables and canonicalize path [[ -n ${PKGDEST} ]] && _PKGDEST=$(canonicalize_path ${PKGDEST}) @@ -1993,13 +2101,14 @@ set -E [[ -n ${PKGEXT} ]] && _PKGEXT=${PKGEXT} [[ -n ${SRCEXT} ]] && _SRCEXT=${SRCEXT} [[ -n ${GPGKEY} ]] && _GPGKEY=${GPGKEY} +[[ -n ${PACKAGER} ]] && _PACKAGER=${PACKAGER} # default config is makepkg.conf MAKEPKG_CONF=${MAKEPKG_CONF:-$confdir/makepkg.conf} # Source the config file; fail if it is not found if [[ -r $MAKEPKG_CONF ]]; then - source "$MAKEPKG_CONF" + source_safe "$MAKEPKG_CONF" else error "$(gettext "%s not found.")" "$MAKEPKG_CONF" plain "$(gettext "Aborting...")" @@ -2009,7 +2118,7 @@ fi # Source user-specific makepkg.conf overrides, but only if no override config # file was specified if [[ $MAKEPKG_CONF = "$confdir/makepkg.conf" && -r ~/.makepkg.conf ]]; then - source ~/.makepkg.conf + source_safe ~/.makepkg.conf fi # set pacman command if not already defined @@ -2017,7 +2126,7 @@ PACMAN=${PACMAN:-pacman} # check if messages are to be printed using color unset ALL_OFF BOLD BLUE GREEN RED YELLOW -if [[ -t 2 && ! $USE_COLOR = "n" && $(check_buildenv color) = "y" ]]; then +if [[ -t 2 && ! $USE_COLOR = "n" ]] && check_buildenv "color" "y"; then # prefer terminal safe colored and bold text when tput is supported if tput setaf 0 &>/dev/null; then ALL_OFF="$(tput sgr0)" @@ -2041,8 +2150,11 @@ readonly ALL_OFF BOLD BLUE GREEN RED YELLOW BUILDDIR=${_BUILDDIR:-$BUILDDIR} BUILDDIR=${BUILDDIR:-$startdir} #default to $startdir if undefined if [[ ! -d $BUILDDIR ]]; then - mkdir -p "$BUILDDIR" || - error "$(gettext "You do not have write permission to create packages in %s.")" "$BUILDDIR" + if ! mkdir -p "$BUILDDIR"; then + error "$(gettext "You do not have write permission to create packages in %s.")" "$BUILDDIR" + plain "$(gettext "Aborting...")" + exit 1 + fi chmod a-s "$BUILDDIR" fi if [[ ! -w $BUILDDIR ]]; then @@ -2050,8 +2162,6 @@ if [[ ! -w $BUILDDIR ]]; then plain "$(gettext "Aborting...")" exit 1 fi -srcdir="$BUILDDIR/src" -pkgdir="$BUILDDIR/pkg" PKGDEST=${_PKGDEST:-$PKGDEST} PKGDEST=${PKGDEST:-$startdir} #default to $startdir if undefined @@ -2080,6 +2190,7 @@ fi PKGEXT=${_PKGEXT:-$PKGEXT} SRCEXT=${_SRCEXT:-$SRCEXT} GPGKEY=${_GPGKEY:-$GPGKEY} +PACKAGER=${_PACKAGER:-$PACKAGER} if (( HOLDVER )) && [[ -n $FORCE_VER ]]; then # The '\\0' is here to prevent gettext from thinking --holdver is an option @@ -2099,7 +2210,7 @@ use the %s option.")" "makepkg" "--asroot" error "$(gettext "The %s option is meant for the root user only. Please\n\ rerun %s without the %s flag.")" "--asroot" "makepkg" "--asroot" exit 1 # $E_USER_ABORT - elif (( EUID > 0 )) && [[ $(check_buildenv fakeroot) != "y" ]]; then + elif (( EUID > 0 )) && ! check_buildenv "fakeroot" "y"; then warning "$(gettext "Running %s as an unprivileged user will result in non-root\n\ ownership of the packaged files. Try using the %s environment by\n\ placing %s in the %s array in %s.")" "makepkg" "fakeroot" "'fakeroot'" "BUILDENV" "$MAKEPKG_CONF" @@ -2124,9 +2235,7 @@ if [[ ! -f $BUILDFILE ]]; then else # PKGBUILD passed through a pipe BUILDFILE=/dev/stdin - shopt -u extglob - source "$BUILDFILE" - shopt -s extglob + source_safe "$BUILDFILE" fi else crlftest=$(file "$BUILDFILE" | grep -F 'CRLF' || true) @@ -2138,19 +2247,25 @@ else if [[ ${BUILDFILE:0:1} != "/" ]]; then BUILDFILE="$startdir/$BUILDFILE" fi - shopt -u extglob - source "$BUILDFILE" - shopt -s extglob + source_safe "$BUILDFILE" fi # set defaults if they weren't specified in buildfile pkgbase=${pkgbase:-${pkgname[0]}} epoch=${epoch:-0} +if [[ $BUILDDIR = "$startdir" ]]; then + srcdir="$BUILDDIR/src" + pkgdir="$BUILDDIR/pkg" +else + srcdir="$BUILDDIR/$pkgbase/src" + pkgdir="$BUILDDIR/$pkgbase/pkg" +fi + if (( GENINTEG )); then mkdir -p "$srcdir" chmod a-s "$srcdir" - cd "$srcdir" + cd_safe "$srcdir" download_sources generate_checksums exit 0 # $E_OK @@ -2174,12 +2289,15 @@ if (( ${#pkgname[@]} > 1 )); then fi # test for available PKGBUILD functions +if declare -f prepare >/dev/null; then + PREPAREFUNC=1 +fi if declare -f build >/dev/null; then BUILDFUNC=1 fi if declare -f check >/dev/null; then # "Hide" check() function if not going to be run - if [[ $RUN_CHECK = 'y' || (! $(check_buildenv check) = "n" && ! $RUN_CHECK = "n") ]]; then + if [[ $RUN_CHECK = 'y' ]] || { ! check_buildenv "check" "n" && [[ $RUN_CHECK != "n" ]]; }; then CHECKFUNC=1 fi fi @@ -2195,8 +2313,7 @@ if [[ -n "${PKGLIST[@]}" ]]; then fi # check if gpg signature is to be created and if signing key is valid -[[ -z $SIGNPKG ]] && SIGNPKG=$(check_buildenv sign) -if [[ $SIGNPKG == 'y' ]]; then +if { [[ -z $SIGNPKG ]] && check_buildenv "sign" "y"; } || [[ $SIGNPKG == 'y' ]]; then if ! gpg --list-key ${GPGKEY} &>/dev/null; then if [[ ! -z $GPGKEY ]]; then error "$(gettext "The key %s does not exist in your keyring.")" "${GPGKEY}" @@ -2210,8 +2327,8 @@ fi if (( ! SPLITPKG )); then fullver=$(get_full_version) - if [[ -f $PKGDEST/${pkgname}-${fullver}-${CARCH}${PKGEXT} \ - || -f $PKGDEST/${pkgname}-${fullver}-any${PKGEXT} ]] \ + pkgarch=$(get_pkg_arch) + if [[ -f $PKGDEST/${pkgname}-${fullver}-${pkgarch}${PKGEXT} ]] \ && ! (( FORCE || SOURCEONLY || NOBUILD )); then if (( INSTALL )); then warning "$(gettext "A package has already been built, installing existing package...")" @@ -2227,8 +2344,8 @@ else somepkgbuilt=0 for pkg in ${pkgname[@]}; do fullver=$(get_full_version $pkg) - if [[ -f $PKGDEST/${pkg}-${fullver}-${CARCH}${PKGEXT} \ - || -f $PKGDEST/${pkg}-${fullver}-any${PKGEXT} ]]; then + pkgarch=$(get_pkg_arch $pkg) + if [[ -f $PKGDEST/${pkg}-${fullver}-${pkgarch}${PKGEXT} ]]; then somepkgbuilt=1 else allpkgbuilt=0 @@ -2300,17 +2417,17 @@ if (( SOURCEONLY )); then # Get back to our src directory so we can begin with sources. mkdir -p "$srcdir" chmod a-s "$srcdir" - cd "$srcdir" + cd_safe "$srcdir" if ( (( ! SKIPCHECKSUMS )) || \ ( (( ! SKIPPGPCHECK )) && source_has_signatures ) ) || \ (( SOURCEONLY == 2 )); then download_sources fi check_source_integrity - cd "$startdir" + cd_safe "$startdir" # if we are root or if fakeroot is not enabled, then we don't use it - if [[ $(check_buildenv fakeroot) != "y" ]] || (( EUID == 0 )); then + if ! check_buildenv "fakeroot" "y" || (( EUID == 0 )); then create_srcpackage else enter_fakeroot @@ -2320,9 +2437,9 @@ if (( SOURCEONLY )); then exit 0 fi -if (( NODEPS || ( (NOBUILD || REPKG) && !DEP_BIN ) )); then - # no warning message needed for nobuild, repkg - if (( NODEPS || ( REPKG && PKGFUNC ) )); then +if (( NODEPS || (NOBUILD && !DEP_BIN ) )); then + # no warning message needed for nobuild + if (( NODEPS )); then warning "$(gettext "Skipping dependency checks.")" fi elif type -p "${PACMAN%% *}" >/dev/null; then @@ -2363,7 +2480,7 @@ umask 0022 # get back to our src directory so we can begin with sources mkdir -p "$srcdir" chmod a-s "$srcdir" -cd "$srcdir" +cd_safe "$srcdir" if (( NOEXTRACT )); then warning "$(gettext "Skipping source retrieval -- using existing %s tree")" "src/" @@ -2386,6 +2503,9 @@ else download_sources check_source_integrity extract_sources + if (( PREPAREFUNC )); then + run_prepare + fi fi if (( NOBUILD )); then @@ -2399,10 +2519,10 @@ else fi mkdir -p "$pkgdir" chmod a-s "$pkgdir" - cd "$startdir" + cd_safe "$startdir" # if we are root or if fakeroot is not enabled, then we don't use it - if [[ $(check_buildenv fakeroot) != "y" ]] || (( EUID == 0 )); then + if ! check_buildenv "fakeroot" "y" || (( EUID == 0 )); then if (( ! REPKG )); then devel_update (( BUILDFUNC )) && run_build @@ -2429,7 +2549,7 @@ else devel_update (( BUILDFUNC )) && run_build (( CHECKFUNC )) && run_check - cd "$startdir" + cd_safe "$startdir" fi enter_fakeroot diff --git a/scripts/pacman-db-upgrade.sh.in b/scripts/pacman-db-upgrade.sh.in index e0a049c5..894152f6 100644 --- a/scripts/pacman-db-upgrade.sh.in +++ b/scripts/pacman-db-upgrade.sh.in @@ -23,7 +23,7 @@ export TEXTDOMAIN='pacman-scripts' export TEXTDOMAINDIR='@localedir@' -myver='@PACKAGE_VERSION@' +declare -r myver='@PACKAGE_VERSION@' eval $(awk '/DBPath/ {print $1$2$3}' @sysconfdir@/pacman.conf) dbroot="${DBPath:-@localstatedir@/lib/pacman/}" diff --git a/scripts/pacman-key.sh.in b/scripts/pacman-key.sh.in index 948c8d52..e5b60214 100644 --- a/scripts/pacman-key.sh.in +++ b/scripts/pacman-key.sh.in @@ -24,7 +24,7 @@ export TEXTDOMAIN='pacman-scripts' export TEXTDOMAINDIR='@localedir@' -myver="@PACKAGE_VERSION@" +declare -r myver="@PACKAGE_VERSION@" # Options ADD=0 @@ -49,40 +49,43 @@ DEFAULT_KEYSERVER='hkp://pool.sks-keyservers.net' m4_include(library/output_format.sh) -m4_include(library/parse_options.sh) +m4_include(library/parseopts.sh) usage() { printf "pacman-key (pacman) %s\n" ${myver} echo - printf -- "$(gettext "Usage: %s [options]")\n" $(basename $0) + printf -- "$(gettext "Usage: %s [options] operation [targets]")\n" $(basename $0) echo printf -- "$(gettext "Manage pacman's list of trusted keys")\n" echo - printf -- "$(gettext "Options:")\n" - printf -- "$(gettext " -a, --add [file(s)] Add the specified keys (empty for stdin)")\n" - printf -- "$(gettext " -d, --delete <keyid(s)> Remove the specified keyids")\n" - printf -- "$(gettext " -e, --export [keyid(s)] Export the specified or all keyids")\n" - printf -- "$(gettext " -f, --finger [keyid(s)] List fingerprint for specified or all keyids")\n" - printf -- "$(gettext " -h, --help Show this help message and exit")\n" - printf -- "$(gettext " -l, --list-keys [keyid(s)] List the specified or all keys")\n" - printf -- "$(gettext " -r, --recv-keys <keyid(s)> Fetch the specified keyids")\n" + printf -- "$(gettext "Operations:")\n" + printf -- "$(gettext " -a, --add Add the specified keys (empty for stdin)")\n" + printf -- "$(gettext " -d, --delete Remove the specified keyids")\n" + printf -- "$(gettext " -e, --export Export the specified or all keyids")\n" + printf -- "$(gettext " -f, --finger List fingerprint for specified or all keyids")\n" + printf -- "$(gettext " -l, --list-keys List the specified or all keys")\n" + printf -- "$(gettext " -r, --recv-keys Fetch the specified keyids")\n" printf -- "$(gettext " -u, --updatedb Update the trustdb of pacman")\n" - printf -- "$(gettext " -v, --verify <signature> Verify the file specified by the signature")\n" - printf -- "$(gettext " -V, --version Show program version")\n" + printf -- "$(gettext " -v, --verify Verify the file(s) specified by the signature(s)")\n" + printf -- "$(gettext " --edit-key Present a menu for key management task on keyids")\n" + printf -- "$(gettext " --import Imports pubring.gpg from dir(s)")\n" + printf -- "$(gettext " --import-trustdb Imports ownertrust values from trustdb.gpg in dir(s)")\n" + printf -- "$(gettext " --init Ensure the keyring is properly initialized")\n" + printf -- "$(gettext " --list-sigs List keys and their signatures")\n" + printf -- "$(gettext " --lsign-key Locally sign the specified keyid")\n" + printf -- "$(gettext " --populate Reload the default keys from the (given) keyrings\n\ + in '%s'")\n" "@pkgdatadir@/keyrings" + printf -- "$(gettext " --refresh-keys Update specified or all keys from a keyserver")\n" + echo + printf -- "$(gettext "Options:")\n" printf -- "$(gettext " --config <file> Use an alternate config file (instead of\n\ '%s')")\n" "@sysconfdir@/pacman.conf" - printf -- "$(gettext " --edit-key <keyid(s)> Present a menu for key management task on keyids")\n" printf -- "$(gettext " --gpgdir <dir> Set an alternate directory for GnuPG (instead\n\ of '%s')")\n" "@sysconfdir@/pacman.d/gnupg" - printf -- "$(gettext " --import <dir(s)> Imports pubring.gpg from dir(s)")\n" - printf -- "$(gettext " --import-trustdb <dir(s)> Imports ownertrust values from trustdb.gpg in dir(s)")\n" - printf -- "$(gettext " --init Ensure the keyring is properly initialized")\n" - printf -- "$(gettext " --keyserver Specify a keyserver to use if necessary")\n" - printf -- "$(gettext " --list-sigs [keyid(s)] List keys and their signatures")\n" - printf -- "$(gettext " --lsign-key <keyid> Locally sign the specified keyid")\n" - printf -- "$(gettext " --populate [keyring(s)] Reload the default keys from the (given) keyrings\n\ - in '%s'")\n" "@pkgdatadir@/keyrings" - printf -- "$(gettext " --refresh-keys [keyid(s)] Update specified or all keys from a keyserver")\n" + printf -- "$(gettext " --keyserver <server-url> Specify a keyserver to use if necessary")\n" + echo + printf -- "$(gettext " -h, --help Show this help message and exit")\n" + printf -- "$(gettext " -V, --version Show program version")\n" } version() { @@ -113,6 +116,30 @@ get_from() { return 1 } +key_lookup_from_name() { + local ids + + mapfile -t ids < \ + <("${GPG_PACMAN[@]}" --search-keys --batch --with-colons "$1" 2>/dev/null | + awk -F: '$1 == "pub" { print $2 }') + + # only return success on non-ambiguous lookup + case ${#ids[*]} in + 0) + error "$(gettext "Failed to lookup key by name:") %s" "$name" + return 1 + ;; + 1) + printf '%s' "${ids[0]}" + return 0 + ;; + *) + error "$(gettext "Key name is ambiguous:") %s" "$name" + return 1 + ;; + esac +} + generate_master_key() { # Generate the master key, which will be in both pubring and secring "${GPG_PACMAN[@]}" --gen-key --batch <<EOF @@ -146,7 +173,7 @@ add_gpg_conf_option() { check_keyids_exist() { local ret=0 - for key in "${KEYIDS[@]}"; do + for key in "$@"; do # Verify if the key exists in pacman's keyring if ! "${GPG_PACMAN[@]}" --list-keys "$key" &>/dev/null ; then error "$(gettext "The key identified by %s could not be found locally.")" "$key" @@ -217,16 +244,16 @@ check_keyring() { populate_keyring() { local KEYRING_IMPORT_DIR='@pkgdatadir@/keyrings' - local keyring + local keyring KEYRINGIDS=("$@") local ret=0 - if [[ -z ${KEYRINGIDS[@]} ]]; then + if (( ${#KEYRINGIDS[*]} == 0 )); then # get list of all available keyrings shopt -s nullglob KEYRINGIDS=("$KEYRING_IMPORT_DIR"/*.gpg) shopt -u nullglob KEYRINGIDS=("${KEYRINGIDS[@]##*/}") KEYRINGIDS=("${KEYRINGIDS[@]%.gpg}") - if [[ -z ${KEYRINGIDS[@]} ]]; then + if (( ${#KEYRINGIDS[*]} == 0 )); then error "$(gettext "No keyring files exist in %s.")" "$KEYRING_IMPORT_DIR" ret=1 fi @@ -245,8 +272,7 @@ populate_keyring() { fi # Variable used for iterating on keyrings - local key - local key_id + local keys key_id # Add keys from requested keyrings for keyring in "${KEYRINGIDS[@]}"; do @@ -262,14 +288,12 @@ populate_keyring() { local -A trusted_ids for keyring in "${KEYRINGIDS[@]}"; do if [[ -s "${KEYRING_IMPORT_DIR}/${keyring}-trusted" ]]; then - while read key; do - # skip comments; these are valid in this file - [[ $key = \#* ]] && continue - key_id="${key%%:*}" - if [[ -n ${key_id} ]]; then - # Mark this key to be lsigned - trusted_ids[$key_id]="${keyring}" - fi + while IFS=: read key_id _; do + # skip blank lines, comments; these are valid in this file + [[ -z $key_id || ${key_id:0:1} = \# ]] && continue + + # Mark this key to be lsigned + trusted_ids[$key_id]=$keyring done < "${KEYRING_IMPORT_DIR}/${keyring}-trusted" fi done @@ -278,7 +302,7 @@ populate_keyring() { msg "$(gettext "Locally signing trusted keys in keyring...")" for key_id in "${!trusted_ids[@]}"; do msg2 "$(gettext "Locally signing key %s...")" "${key_id}" - "${GPG_PACMAN[@]}" --quiet --lsign-key "${key_id}" + lsign_keys "${key_id}" done msg "$(gettext "Importing owner trust values...")" for keyring in "${KEYRINGIDS[@]}"; do @@ -294,13 +318,13 @@ populate_keyring() { local -A revoked_ids for keyring in "${KEYRINGIDS[@]}"; do if [[ -s "${KEYRING_IMPORT_DIR}/${keyring}-revoked" ]]; then - while read key; do - key_id="$("${GPG_PACMAN[@]}" --quiet --with-colons --list-key "${key}" 2>/dev/null | grep ^pub | cut -d: -f5)" - if [[ -n ${key_id} ]]; then + mapfile -t keys < "${KEYRING_IMPORT_DIR}/${keyring}-revoked" + while IFS=: read _ _ _ _ key_id _; do + if [[ -n $key_id ]]; then # Mark this key to be disabled revoked_ids[$key_id]="${keyring}" fi - done < "${KEYRING_IMPORT_DIR}/${keyring}-revoked" + done < <("${GPG_PACMAN[@]}" --quiet --with-colons --list-keys "${keys[@]}" 2>/dev/null) fi done @@ -314,24 +338,24 @@ populate_keyring() { } add_keys() { - if ! "${GPG_PACMAN[@]}" --quiet --batch --import "${KEYFILES[@]}" ; then + if ! "${GPG_PACMAN[@]}" --quiet --batch --import "$@" ; then error "$(gettext "A specified keyfile could not be added to the keyring.")" exit 1 fi } delete_keys() { - check_keyids_exist - if ! "${GPG_PACMAN[@]}" --quiet --batch --delete-key --yes "${KEYIDS[@]}" ; then + check_keyids_exist "$@" + if ! "${GPG_PACMAN[@]}" --quiet --batch --delete-key --yes "$@" ; then error "$(gettext "A specified key could not be removed from the keyring.")" exit 1 fi } edit_keys() { - check_keyids_exist + check_keyids_exist "$@" local ret=0 - for key in "${KEYIDS[@]}"; do + for key in "$@"; do if ! "${GPG_PACMAN[@]}" --edit-key "$key" ; then error "$(gettext "The key identified by %s could not be edited.")" "$key" ret=1 @@ -343,8 +367,8 @@ edit_keys() { } export_keys() { - check_keyids_exist - if ! "${GPG_PACMAN[@]}" --armor --export "${KEYIDS[@]}" ; then + check_keyids_exist "$@" + if ! "${GPG_PACMAN[@]}" --armor --export "$@" ; then error "$(gettext "A specified key could not be exported from the keyring.")" exit 1 fi @@ -352,7 +376,7 @@ export_keys() { finger_keys() { check_keyids_exist - if ! "${GPG_PACMAN[@]}" --batch --fingerprint "${KEYIDS[@]}" ; then + if ! "${GPG_PACMAN[@]}" --batch --fingerprint "$@" ; then error "$(gettext "The fingerprint of a specified key could not be determined.")" exit 1 fi @@ -361,7 +385,7 @@ finger_keys() { import_trustdb() { local importdir local ret=0 - for importdir in "${IMPORT_DIRS[@]}"; do + for importdir in "$@"; do if [[ -f "${importdir}/trustdb.gpg" ]]; then gpg --homedir "${importdir}" --export-ownertrust | \ "${GPG_PACMAN[@]}" --import-ownertrust - @@ -382,7 +406,7 @@ import_trustdb() { import() { local importdir local ret=0 - for importdir in "${IMPORT_DIRS[@]}"; do + for importdir in "$@"; do if [[ -f "${importdir}/pubring.gpg" ]]; then if ! "${GPG_PACMAN[@]}" --quiet --batch --import "${importdir}/pubring.gpg" ; then error "$(gettext "%s could not be imported.")" "${importdir}/pubring.gpg" @@ -400,7 +424,7 @@ import() { list_keys() { check_keyids_exist - if ! "${GPG_PACMAN[@]}" --batch --list-keys "${KEYIDS[@]}" ; then + if ! "${GPG_PACMAN[@]}" --batch --list-keys "$@" ; then error "$(gettext "A specified key could not be listed.")" exit 1 fi @@ -408,7 +432,7 @@ list_keys() { list_sigs() { check_keyids_exist - if ! "${GPG_PACMAN[@]}" --batch --list-sigs "${KEYIDS[@]}" ; then + if ! "${GPG_PACMAN[@]}" --batch --list-sigs "$@" ; then error "$(gettext "A specified signature could not be listed.")" exit 1 fi @@ -416,7 +440,8 @@ list_sigs() { lsign_keys() { check_keyids_exist - printf 'y\ny\n' | LANG=C "${GPG_PACMAN[@]}" --command-fd 0 --quiet --batch --lsign-key "${KEYIDS[@]}" 2>/dev/null + # we cannot use --yes here as gpg would still ask for confirmation if a key has more than one uid + printf 'y\ny\n' | LANG=C "${GPG_PACMAN[@]}" --command-fd 0 --quiet --batch --lsign-key "$@" 2>/dev/null if (( PIPESTATUS[1] )); then error "$(gettext "A specified key could not be locally signed.")" exit 1 @@ -424,25 +449,45 @@ lsign_keys() { } receive_keys() { - if ! "${GPG_PACMAN[@]}" --recv-keys "${KEYIDS[@]}" ; then + local name id keyids + + # if the key is not a hex ID, do a lookup + for name; do + if [[ $name = ?(0x)+([0-9a-fA-F]) ]]; then + keyids+=("$name") + else + if id=$(key_lookup_from_name "$name"); then + keyids+=("$id") + fi + fi + done + + (( ${#keyids[*]} > 0 )) || exit 1 + + if ! "${GPG_PACMAN[@]}" --recv-keys "${keyids[@]}" ; then error "$(gettext "Remote key not fetched correctly from keyserver.")" exit 1 fi } refresh_keys() { - check_keyids_exist - if ! "${GPG_PACMAN[@]}" --refresh-keys "${KEYIDS[@]}" ; then + check_keyids_exist "$@" + if ! "${GPG_PACMAN[@]}" --refresh-keys "$@" ; then error "$(gettext "A specified local key could not be updated from a keyserver.")" exit 1 fi } verify_sig() { - if ! "${GPG_PACMAN[@]}" --status-fd 1 --verify $SIGNATURE | grep -qE 'TRUST_(FULLY|ULTIMATE)'; then - error "$(gettext "The signature identified by %s could not be verified.")" "$SIGNATURE" - exit 1 - fi + local ret=0 + for sig; do + msg "Checking %s ..." "$sig" + if ! "${GPG_PACMAN[@]}" --status-fd 1 --verify "$sig" | grep -qE 'TRUST_(FULLY|ULTIMATE)'; then + error "$(gettext "The signature identified by %s could not be verified.")" "$sig" + ret=1 + fi + done + exit $ret } updatedb() { @@ -460,56 +505,55 @@ if ! type gettext &>/dev/null; then } fi -OPT_SHORT="a::d:e::f::hl::r:uv:V" -OPT_LONG="add::,config:,delete:,edit-key:,export::,finger::,gpgdir:" -OPT_LONG+=",help,import:,import-trustdb:,init,keyserver:,list-keys::,list-sigs::" -OPT_LONG+=",lsign-key:,populate::,recv-keys:,refresh-keys::,updatedb" -OPT_LONG+=",verify:,version" -if ! OPT_TEMP="$(parse_options $OPT_SHORT $OPT_LONG "$@")"; then - echo; usage; exit 1 # E_INVALID_OPTION; +OPT_SHORT="adefhlruvV" +OPT_LONG=('add' 'config:' 'delete' 'edit-key' 'export' 'finger' 'gpgdir:' + 'help' 'import' 'import-trustdb' 'init' 'keyserver:' 'list-keys' 'list-sigs' + 'lsign-key' 'populate' 'recv-keys' 'refresh-keys' 'updatedb' + 'verify' 'version') +if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then + exit 1 # E_INVALID_OPTION; fi -eval set -- "$OPT_TEMP" -unset OPT_SHORT OPT_LONG OPT_TEMP +set -- "${OPTRET[@]}" +unset OPT_SHORT OPT_LONG OPTRET if [[ $1 == "--" ]]; then usage; exit 0; fi -while true; do - case "$1" in - -a|--add) ADD=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYFILES=($1); UPDATEDB=1 ;; +while (( $# )); do + case $1 in + -a|--add) ADD=1 UPDATEDB=1 ;; --config) shift; CONFIG=$1 ;; - -d|--delete) DELETE=1; shift; KEYIDS=($1); UPDATEDB=1 ;; - --edit-key) EDITKEY=1; shift; KEYIDS=($1); UPDATEDB=1 ;; - -e|--export) EXPORT=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; - -f|--finger) FINGER=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; + -d|--delete) DELETE=1 UPDATEDB=1 ;; + --edit-key) EDITKEY=1 UPDATEDB=1 ;; + -e|--export) EXPORT=1 ;; + -f|--finger) FINGER=1 ;; --gpgdir) shift; PACMAN_KEYRING_DIR=$1 ;; - --import) IMPORT=1; shift; IMPORT_DIRS=($1); UPDATEDB=1 ;; - --import-trustdb) IMPORT_TRUSTDB=1; shift; IMPORT_DIRS=($1); UPDATEDB=1 ;; + --import) IMPORT=1 UPDATEDB=1 ;; + --import-trustdb) IMPORT_TRUSTDB=1 UPDATEDB=1 ;; --init) INIT=1 ;; --keyserver) shift; KEYSERVER=$1 ;; - -l|--list-keys) LISTKEYS=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; - --list-sigs) LISTSIGS=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; - --lsign-key) LSIGNKEY=1; shift; KEYIDS=($1); UPDATEDB=1 ;; - --populate) POPULATE=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYRINGIDS=($1); UPDATEDB=1 ;; - -r|--recv-keys) RECEIVE=1; shift; KEYIDS=($1); UPDATEDB=1 ;; - --refresh-keys) REFRESH=1; [[ -n $2 && ${2:0:1} != "-" ]] && shift && KEYIDS=($1) ;; + -l|--list-keys) LISTKEYS=1 ;; + --list-sigs) LISTSIGS=1 ;; + --lsign-key) LSIGNKEY=1 UPDATEDB=1 ;; + --populate) POPULATE=1 UPDATEDB=1 ;; + -r|--recv-keys) RECEIVE=1 UPDATEDB=1 ;; + --refresh-keys) REFRESH=1 ;; -u|--updatedb) UPDATEDB=1 ;; - -v|--verify) VERIFY=1; shift; SIGNATURE=$1 ;; + -v|--verify) VERIFY=1 ;; -h|--help) usage; exit 0 ;; -V|--version) version; exit 0 ;; - --) OPT_IND=0; shift; break;; - *) usage; exit 1 ;; + --) shift; break 2 ;; esac shift done if ! type -p gpg >/dev/null; then - error "$(gettext "Cannot find the %s binary required for all %s operations.")" "gpg" "pacman-key" + error "$(gettext "Cannot find the %s binary required for all %s operations.")" "gpg" "pacman-key" exit 1 fi @@ -552,23 +596,30 @@ case $numopt in ;; esac +# check for targets where needed +if (( (ADD || DELETE || EDIT || IMPORT || IMPORT_TRUSTDB || + LSIGNKEY || RECEIVE || VERIFY) && $# == 0 )); then + error "$(gettext "No targets specified")" + exit 1 +fi + (( ! INIT )) && check_keyring -(( ADD )) && add_keys -(( DELETE )) && delete_keys -(( EDITKEY )) && edit_keys -(( EXPORT )) && export_keys -(( FINGER )) && finger_keys -(( IMPORT )) && import -(( IMPORT_TRUSTDB)) && import_trustdb +(( ADD )) && add_keys "$@" +(( DELETE )) && delete_keys "$@" +(( EDITKEY )) && edit_keys "$@" +(( EXPORT )) && export_keys "$@" +(( FINGER )) && finger_keys "$@" +(( IMPORT )) && import "$@" +(( IMPORT_TRUSTDB)) && import_trustdb "$@" (( INIT )) && initialize -(( LISTKEYS )) && list_keys -(( LISTSIGS )) && list_sigs -(( LSIGNKEY )) && lsign_keys -(( POPULATE )) && populate_keyring -(( RECEIVE )) && receive_keys -(( REFRESH )) && refresh_keys -(( VERIFY )) && verify_sig +(( LISTKEYS )) && list_keys "$@" +(( LISTSIGS )) && list_sigs "$@" +(( LSIGNKEY )) && lsign_keys "$@" +(( POPULATE )) && populate_keyring "$@" +(( RECEIVE )) && receive_keys "$@" +(( REFRESH )) && refresh_keys "$@" +(( VERIFY )) && verify_sig "$@" (( UPDATEDB )) && updatedb diff --git a/scripts/pacman-optimize.sh.in b/scripts/pacman-optimize.sh.in index 8a4e7224..4a84c0bb 100644 --- a/scripts/pacman-optimize.sh.in +++ b/scripts/pacman-optimize.sh.in @@ -24,7 +24,7 @@ export TEXTDOMAIN='pacman-scripts' export TEXTDOMAINDIR='@localedir@' -myver='@PACKAGE_VERSION@' +declare -r myver='@PACKAGE_VERSION@' eval $(awk '/DBPath/ {print $1$2$3}' @sysconfdir@/pacman.conf) dbroot="${DBPath:-@localstatedir@/lib/pacman/}" @@ -88,9 +88,8 @@ if [[ -n $1 ]]; then dbroot="$1" fi -# make sure diff is installed -if ! type diff >/dev/null 2>&1; then - die "$(gettext "diff tool was not found, please install diffutils.")" +if ! type -p openssl >/dev/null; then + die "$(gettext "Cannot find the %s binary required for verifying integrity.")" "openssl" fi if [[ ! -d $dbroot || ! -d $dbroot/local ]]; then @@ -103,8 +102,8 @@ fi # strip any trailing slash from our dbroot dbroot="${dbroot%/}" -# form the path to our lockfile location lockfile="${dbroot}/db.lck" +localdb="${dbroot}/local" # make sure pacman isn't running if [[ -f $lockfile ]]; then @@ -113,42 +112,44 @@ fi # do not let pacman run while we do this touch "$lockfile" -workdir=$(mktemp -d /tmp/pacman-optimize.XXXXXXXXXX) || +workdir=$(mktemp -d "${TMPDIR:-/tmp}/pacman-optimize.XXXXXXXXXX") || die_r "$(gettext "Can not create temp directory for database building.")\n" >&2 # step 1: sum the old db msg "$(gettext "MD5sum'ing the old database...")" -find "$dbroot" -type f | sort | xargs md5sum > "$workdir/pacsums.old" +(cd "$localdb" && find . -type f -print0 | \ + xargs -0 openssl dgst -md5 | sort > "$workdir/pacsums.old") # step 2: tar it up -msg "$(gettext "Tar'ing up %s...")" "$dbroot" -bsdtar -czf "$workdir/pacman-db.tar.gz" -C "$dbroot" ./ +msg "$(gettext "Tar'ing up %s...")" "$localdb" +bsdtar -czf "$workdir/pacman-db.tar.gz" -C "$localdb" ./ if (( $? )); then rm -rf "$workdir" - die_r "$(gettext "Tar'ing up %s failed.")" "$dbroot" + die_r "$(gettext "Tar'ing up %s failed.")" "$localdb" fi # step 3: make and sum the new db side-by-side with the old msg "$(gettext "Making and MD5sum'ing the new database...")" -mkdir "$dbroot.new" -bsdtar -xpf "$workdir/pacman-db.tar.gz" -C "$dbroot.new" +mkdir "$localdb.new" +bsdtar -xpf "$workdir/pacman-db.tar.gz" -C "$localdb.new" if (( $? )); then rm -rf "$workdir" - die_r "$(gettext "Untar'ing %s failed.")" "$dbroot" + die_r "$(gettext "Untar'ing %s failed.")" "$localdb" fi # immediate sync following extraction should get it written continuously on HDD msg "$(gettext "Syncing database to disk...")" sync -find "$dbroot.new" -type f | sort | \ - xargs md5sum | sed 's#.new##' > "$workdir/pacsums.new" +(cd "$localdb.new" && find . -type f -print0 | \ + xargs -0 openssl dgst -md5 | sort > "$workdir/pacsums.new") # step 4: compare the sums msg "$(gettext "Checking integrity...")" -diff "$workdir/pacsums.old" "$workdir/pacsums.new" >/dev/null 2>&1 -if (( $? )); then +read -ra old_dgst < <(openssl dgst -md5 < "$workdir/pacsums.old") +read -ra new_dgst < <(openssl dgst -md5 < "$workdir/pacsums.new") +if [[ ${old_dgst[@]:(-1)} != ${new_dgst[@]:(-1)} ]]; then # failed # leave our pacman-optimize tmpdir for checking to see what doesn't match up - rm -rf "$dbroot.new" + rm -rf "$localdb.new" die_r "$(gettext "Integrity check FAILED, reverting to old database.")" fi @@ -156,15 +157,15 @@ fi msg "$(gettext "Rotating database into place...")" fail=0 -mv "$dbroot" "$dbroot.old" || fail=1 -mv "$dbroot.new" "$dbroot" || fail=1 -chmod --reference="$dbroot.old" "$dbroot" || fail=1 -chown --reference="$dbroot.old" "$dbroot" || fail=1 +mv "$localdb" "$localdb.old" || fail=1 +mv "$localdb.new" "$localdb" || fail=1 +chmod --reference="$localdb.old" "$localdb" || fail=1 +chown --reference="$localdb.old" "$localdb" || fail=1 if (( fail )); then # failure with our directory shuffle - die_r "$(gettext "New database substitution failed. Check for $dbroot,\n$dbroot.old, and $dbroot.new directories.")" + die_r "$(gettext "New database substitution failed. Check for %s, %s, and %s directories.")" "$localdb" "$localdb.old" "$localdb.new" fi -rm -rf "$dbroot.old" +rm -rf "$localdb.old" # remove the lock file and our working directory with sums and tarfile rm -f "$lockfile" diff --git a/scripts/pkgdelta.sh.in b/scripts/pkgdelta.sh.in index ae0bfc38..3d80261f 100644 --- a/scripts/pkgdelta.sh.in +++ b/scripts/pkgdelta.sh.in @@ -26,7 +26,7 @@ set -o errexit export TEXTDOMAIN='pacman-scripts' export TEXTDOMAINDIR='@localedir@' -myver='@PACKAGE_VERSION@' +declare -r myver='@PACKAGE_VERSION@' QUIET=0 @@ -40,6 +40,7 @@ max_delta_size=70 # ensure we have a sane umask set umask 0022 +m4_include(library/parseopts.sh) m4_include(library/output_format.sh) # print usage instructions @@ -53,8 +54,8 @@ This delta file can then be added to a database using repo-add.\n\n")" echo printf -- "$(gettext "Options:\n")" printf -- "$(gettext " -q, --quiet minimize output\n")" - printf -- "$(gettext " --min-pkg-size minimum package size before deltas are generated (bytes)\n")" - printf -- "$(gettext " --max-delta-size percent of package size above which deltas will be discarded\n")" + printf -- "$(gettext " --min-pkg-size minimum package size before deltas are generated\n")" + printf -- "$(gettext " --max-delta-size percent of new package above which the delta will be discarded\n")" } version() { @@ -65,6 +66,8 @@ This is free software; see the source for copying conditions.\n\ There is NO WARRANTY, to the extent permitted by law.\n")" } +m4_include(library/human_to_size.sh) + isnumeric() { [[ $1 != *[!0-9]* ]] } @@ -155,44 +158,52 @@ create_xdelta() return 0 } -declare -a args +OPT_SHORT='hqV' +OPT_LONG=('help' 'quiet' 'max-delta-size:' 'min-pkg-size:' 'version') +if ! parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@"; then + exit 1 +fi +set -- "${OPTRET[@]}" +unset OPT_SHORT OPT_LONG OPTRET # parse arguments -while (( $# )); do - case "$1" in - -h|--help) usage; exit 0 ;; - -V|--version) version; exit 0 ;; - -q|--quiet) QUIET=1;; +while :; do + case $1 in + -h|--help) + usage + exit 0 ;; + -V|--version) + version + exit 0 ;; + -q|--quiet) + QUIET=1;; --min-pkg-size) - if ! isnumeric "$2"; then + if ! min_pkg_size=$(human_to_size "$2"); then echo "invalid argument '$2' for option -- '$1'" exit 1 fi - min_pkg_size=$2 - shift - ;; + shift ;; --max-delta-size) - arg=$(echo "$2" | awk '{print $1 * 100}') - if ! isnumeric "$arg" || (($arg > 200)); then + arg=$(awk -v val="$2" 'BEGIN { print val * 100 }') + if ! isnumeric "$arg" || (( arg > 200 )); then echo "invalid argument '$2' for option -- '$1'" exit 1 fi max_delta_size=$arg + shift ;; + --) shift - ;; - --) shift; args+=("$@"); break 2 ;; - -*) echo "invalid option -- '$1'"; usage; exit 1 ;; - *) args+=("$1");; + break 2 ;; esac shift done -if (( ${#args[@]} != 2 )); then +if (( $# != 2 )); then usage exit 1 fi -for i in "${args[@]}"; do +for i in "$@"; do if [[ ! -f $i ]]; then error "$(gettext "File '%s' does not exist")" "$i" exit 1 diff --git a/scripts/po/POTFILES.in b/scripts/po/POTFILES.in index 007e535f..162731b9 100644 --- a/scripts/po/POTFILES.in +++ b/scripts/po/POTFILES.in @@ -8,4 +8,4 @@ scripts/pacman-optimize.sh.in scripts/pkgdelta.sh.in scripts/repo-add.sh.in scripts/library/output_format.sh -scripts/library/parse_options.sh +scripts/library/parseopts.sh diff --git a/scripts/repo-add.sh.in b/scripts/repo-add.sh.in index 5724022a..504cae97 100644 --- a/scripts/repo-add.sh.in +++ b/scripts/repo-add.sh.in @@ -25,8 +25,8 @@ shopt -s extglob export TEXTDOMAIN='pacman-scripts' export TEXTDOMAINDIR='@localedir@' -myver='@PACKAGE_VERSION@' -confdir='@sysconfdir@' +declare -r myver='@PACKAGE_VERSION@' +declare -r confdir='@sysconfdir@' QUIET=0 DELTA=0 @@ -176,6 +176,11 @@ db_remove_delta() { if grep -q "$filename" "$deltas"; then sed -i.backup "/$filename/d" "$deltas" && rm -f "$deltas.backup" msg2 "$(gettext "Removing existing entry '%s'...")" "$filename" + # empty deltas file contains only "%DELTAS%" + if (( $(wc -l < "$deltas") == 1 )); then + msg2 "$(gettext "Removing empty deltas file ...")" + rm "$deltas" + fi return 0 fi @@ -203,7 +208,7 @@ create_signature() { gpg --detach-sign --use-agent ${SIGNWITHKEY} "$dbfile" &>/dev/null || ret=$? if (( ! ret )); then - msg2 "$(gettext "Created signature file %s.")" "${dbfile##*/}.sig" + msg2 "$(gettext "Created signature file %s.")" "${dbfile##*/.tmp.}.sig" else warning "$(gettext "Failed to sign package database.")" fi @@ -251,7 +256,8 @@ verify_repo_extension() { db_write_entry() { # blank out all variables local pkgfile=$1 - local -a _groups _licenses _replaces _depends _conflicts _provides _optdepends + local -a _groups _licenses _replaces _depends _conflicts _provides \ + _optdepends _makedepends _checkdepends local pkgname pkgver pkgdesc csize size url arch builddate packager \ md5sum sha256sum pgpsig pgpsigsize @@ -264,13 +270,15 @@ db_write_entry() { # normalize whitespace with an extglob declare "$var=${val//+([[:space:]])/ }" case $var in - group) _groups+=("$group") ;; - license) _licenses+=("$license") ;; - replaces) _replaces+=("$replaces") ;; - depend) _depends+=("$depend") ;; - conflict) _conflicts+=("$conflict") ;; - provides) _provides+=("$provides") ;; + group) _groups+=("$group") ;; + license) _licenses+=("$license") ;; + replaces) _replaces+=("$replaces") ;; + depend) _depends+=("$depend") ;; + conflict) _conflicts+=("$conflict") ;; + provides) _provides+=("$provides") ;; optdepend) _optdepends+=("$optdepend") ;; + makedepend) _makedepends+=("$makedepend") ;; + checkdepend) _checkdepends+=("$checkdepend") ;; esac done< <(bsdtar -xOqf "$pkgfile" .PKGINFO) @@ -353,10 +361,12 @@ db_write_entry() { # create depends entry msg2 "$(gettext "Creating '%s' db entry...")" 'depends' { - format_entry "DEPENDS" "${_depends[@]}" - format_entry "CONFLICTS" "${_conflicts[@]}" - format_entry "PROVIDES" "${_provides[@]}" + format_entry "DEPENDS" "${_depends[@]}" + format_entry "CONFLICTS" "${_conflicts[@]}" + format_entry "PROVIDES" "${_provides[@]}" format_entry "OPTDEPENDS" "${_optdepends[@]}" + format_entry "MAKEDEPENDS" "${_makedepends[@]}" + format_entry "CHECKDEPENDS" "${_checkdepends[@]}" } >'depends' popd >/dev/null @@ -424,13 +434,8 @@ elephant() { check_repo_db() { local repodir - # ensure the path to the DB exists - if [[ "$LOCKFILE" == /* ]]; then - repodir=${LOCKFILE%/*}/ - else - repodir=$PWD/$LOCKFILE - repodir=${repodir%/*}/ - fi + # ensure the path to the DB exists; $LOCKFILE is always an absolute path + repodir=${LOCKFILE%/*}/ if [[ ! -d $repodir ]]; then error "$(gettext "%s does not exist or is not a directory.")" "$repodir" @@ -579,7 +584,7 @@ if [[ $cmd != "repo-add" && $cmd != "repo-remove" ]]; then exit 1 fi -tmpdir=$(mktemp -d /tmp/repo-tools.XXXXXXXXXX) || (\ +tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/repo-tools.XXXXXXXXXX") || (\ error "$(gettext "Cannot create temp directory for database building.")"; \ exit 1) mkdir "$tmpdir/tree" @@ -637,7 +642,11 @@ if [[ -z $REPO_DB_FILE ]]; then exit 1 fi -LOCKFILE=$REPO_DB_FILE.lck +if [[ $REPO_DB_FILE == /* ]]; then + LOCKFILE=$REPO_DB_FILE.lck +else + LOCKFILE=$PWD/$REPO_DB_FILE.lck +fi verify_repo_extension "$REPO_DB_FILE" >/dev/null check_repo_db @@ -654,37 +663,51 @@ if (( success )); then msg "$(gettext "Creating updated database file '%s'")" "$REPO_DB_FILE" TAR_OPT=$(verify_repo_extension "$REPO_DB_FILE") + # $LOCKFILE is already guaranteed to be absolute so this is safe + dirname=${LOCKFILE%/*} filename=${REPO_DB_FILE##*/} + # this ensures we create it on the same filesystem, making moves atomic + tempname=$dirname/.tmp.$filename pushd "$tmpdir/tree" >/dev/null if ( shopt -s nullglob; files=(*); (( ${#files[*]} )) ); then - bsdtar -c${TAR_OPT}f "$tmpdir/$filename" * + bsdtar -c${TAR_OPT}f "$tempname" * else # we have no packages remaining? zip up some emptyness warning "$(gettext "No packages remain, creating empty database.")" - bsdtar -c${TAR_OPT}f "$tmpdir/$filename" -T /dev/null + bsdtar -c${TAR_OPT}f "$tempname" -T /dev/null fi popd >/dev/null - create_signature "$tmpdir/$filename" + create_signature "$tempname" - [[ -f $REPO_DB_FILE ]] && mv -f "$REPO_DB_FILE" "${REPO_DB_FILE}.old" + # hardlink or move the previous version of the database and signature to .old + # extension as a backup measure + if [[ -f $REPO_DB_FILE ]]; then + ln -f "$REPO_DB_FILE" "$REPO_DB_FILE.old" 2>/dev/null || \ + mv -f "$REPO_DB_FILE" "$REPO_DB_FILE.old" + fi if [[ -f $REPO_DB_FILE.sig ]]; then - mv -f "$REPO_DB_FILE.sig" "$REPO_DB_FILE.old.sig" + ln -f "$REPO_DB_FILE.sig" "$REPO_DB_FILE.old.sig" 2>/dev/null || \ + mv -f "$REPO_DB_FILE.sig" "$REPO_DB_FILE.old.sig" else rm -f "$REPO_DB_FILE.old.sig" fi - [[ -f $tmpdir/$filename ]] && mv "$tmpdir/$filename" "$REPO_DB_FILE" - [[ -f $tmpdir/$filename.sig ]] && mv "$tmpdir/$filename.sig" "$REPO_DB_FILE.sig" + + # rotate the newly-created database and signature into place + mv "$tempname" "$REPO_DB_FILE" + if [[ -f $tempname.sig ]]; then + mv "$tempname.sig" "$REPO_DB_FILE.sig" + fi + dblink=${REPO_DB_FILE%.tar*} - target=${REPO_DB_FILE##*/} rm -f "$dblink" "$dblink.sig" - ln -s "$target" "$dblink" 2>/dev/null || \ - ln "$target" "$dblink" 2>/dev/null || \ + ln -s "$filename" "$dblink" 2>/dev/null || \ + ln "$filename" "$dblink" 2>/dev/null || \ cp "$REPO_DB_FILE" "$dblink" if [[ -f "$REPO_DB_FILE.sig" ]]; then - ln -s "$target.sig" "$dblink.sig" 2>/dev/null || \ - ln "$target.sig" "$dblink.sig" 2>/dev/null || \ + ln -s "$filename.sig" "$dblink.sig" 2>/dev/null || \ + ln "$filename.sig" "$dblink.sig" 2>/dev/null || \ cp "$REPO_DB_FILE.sig" "$dblink.sig" fi else diff --git a/src/pacman/Makefile.am b/src/pacman/Makefile.am index 3790bdf4..c8ce9773 100644 --- a/src/pacman/Makefile.am +++ b/src/pacman/Makefile.am @@ -11,15 +11,17 @@ bin_PROGRAMS = pacman DEFS = -DLOCALEDIR=\"@localedir@\" \ -DCONFFILE=\"$(conffile)\" \ - -DROOTDIR=\"$(ROOTDIR)\" \ -DDBPATH=\"$(dbpath)\" \ -DGPGDIR=\"$(gpgdir)\" \ -DCACHEDIR=\"$(cachedir)\" \ -DLOGFILE=\"$(logfile)\" \ @DEFS@ -INCLUDES = -I$(top_srcdir)/lib/libalpm -AM_CFLAGS = -pedantic -D_GNU_SOURCE +AM_CPPFLAGS = \ + -imacros $(top_builddir)/config.h \ + -I$(top_srcdir)/lib/libalpm + +AM_CFLAGS = -pedantic -D_GNU_SOURCE $(WARNING_CFLAGS) if USE_GIT_VERSION GIT_VERSION := $(shell sh -c 'git describe --abbrev=4 --dirty | sed s/^v//') diff --git a/src/pacman/callback.c b/src/pacman/callback.c index 344f6a58..01c6b619 100644 --- a/src/pacman/callback.c +++ b/src/pacman/callback.c @@ -1,7 +1,7 @@ /* * callback.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,13 +18,12 @@ * 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 <sys/time.h> #include <sys/types.h> /* off_t */ +#include <time.h> #include <unistd.h> #include <wchar.h> #include <limits.h> /* UINT_MAX */ @@ -44,15 +43,19 @@ static off_t list_total = 0.0; static int on_progress = 0; static alpm_list_t *output = NULL; -/* Silly little helper function, determines if the caller needs a visual update +/* update speed for the fill_progress based functions */ +#define UPDATE_SPEED_MS 200 + +/** + * Silly little helper function, determines if the caller needs a visual update * since the last time this function was called. - * This is made for the two progress bar functions, to prevent flicker - * - * first_call indicates if this is the first time it is called, for - * initialization purposes */ -static double get_update_timediff(int first_call) + * This is made for the two progress bar functions, to prevent flicker. + * @param first_call 1 on first call for initialization purposes, 0 otherwise + * @return number of milliseconds since last call + */ +static long get_update_timediff(int first_call) { - double retval = 0.0; + long retval = 0; static struct timeval last_time = {0, 0}; /* on first call, simply set the last time and return */ @@ -60,18 +63,17 @@ static double get_update_timediff(int first_call) gettimeofday(&last_time, NULL); } else { struct timeval this_time; - double diff_sec, diff_usec; + time_t diff_sec; + suseconds_t diff_usec; gettimeofday(&this_time, NULL); diff_sec = this_time.tv_sec - last_time.tv_sec; diff_usec = this_time.tv_usec - last_time.tv_usec; - retval = diff_sec + (diff_usec / 1000000.0); + retval = (diff_sec * 1000) + (diff_usec / 1000); - /* return 0 and do not update last_time if interval was too short */ - if(retval < UPDATE_SPEED_SEC) { - retval = 0.0; - } else { + /* do not update last_time if interval was too short */ + if(retval >= UPDATE_SPEED_MS) { last_time = this_time; } } @@ -95,41 +97,41 @@ static void fill_progress(const int bar_percent, const int disp_percent, } if(hashlen > 0) { - printf(" ["); + fputs(" [", stdout); for(i = hashlen; i > 0; --i) { /* if special progress bar enabled */ if(config->chomp) { if(i > hashlen - hash) { - printf("-"); + putchar('-'); } else if(i == hashlen - hash) { if(lasthash == hash) { if(mouth) { - printf("\033[1;33mC\033[m"); + fputs("\033[1;33mC\033[m", stdout); } else { - printf("\033[1;33mc\033[m"); + fputs("\033[1;33mc\033[m", stdout); } } else { lasthash = hash; mouth = mouth == 1 ? 0 : 1; if(mouth) { - printf("\033[1;33mC\033[m"); + fputs("\033[1;33mC\033[m", stdout); } else { - printf("\033[1;33mc\033[m"); + fputs("\033[1;33mc\033[m", stdout); } } - } else if(i%3 == 0) { - printf("\033[0;37mo\033[m"); + } else if(i % 3 == 0) { + fputs("\033[0;37mo\033[m", stdout); } else { - printf("\033[0;37m \033[m"); + fputs("\033[0;37m \033[m", stdout); } } /* else regular progress bar */ else if(i > hashlen - hash) { - printf("#"); + putchar('#'); } else { - printf("-"); + putchar('-'); } } - printf("]"); + putchar(']'); } /* print display percent after progress bar */ /* 5 = 1 space + 3 digits + 1 % */ @@ -138,9 +140,9 @@ static void fill_progress(const int bar_percent, const int disp_percent, } if(bar_percent == 100) { - printf("\n"); + putchar('\n'); } else { - printf("\r"); + putchar('\r'); } fflush(stdout); } @@ -196,9 +198,9 @@ void cb_event(alpm_event_t event, void *data1, void *data2) break; case ALPM_EVENT_UPGRADE_DONE: alpm_logaction(config->handle, "upgraded %s (%s -> %s)\n", - (char *)alpm_pkg_get_name(data1), - (char *)alpm_pkg_get_version(data2), - (char *)alpm_pkg_get_version(data1)); + alpm_pkg_get_name(data1), + alpm_pkg_get_version(data2), + alpm_pkg_get_version(data1)); display_new_optdepends(data2,data1); break; case ALPM_EVENT_INTEGRITY_START: @@ -227,10 +229,10 @@ void cb_event(alpm_event_t event, void *data1, void *data2) printf(_("failed.\n")); break; case ALPM_EVENT_SCRIPTLET_INFO: - printf("%s", (char *)data1); + fputs((const char *)data1, stdout); break; case ALPM_EVENT_RETRIEVE_START: - printf(_(":: Retrieving packages from %s...\n"), (char *)data1); + printf(_(":: Retrieving packages ...\n")); break; case ALPM_EVENT_DISKSPACE_START: if(config->noprogressbar) { @@ -294,10 +296,10 @@ void cb_question(alpm_question_t event, void *data1, void *data2, break; case ALPM_QUESTION_REMOVE_PKGS: { - alpm_list_t *unresolved = (alpm_list_t *) data1; + alpm_list_t *unresolved = data1; alpm_list_t *namelist = NULL, *i; size_t count = 0; - for (i = unresolved; i; i = i->next) { + for(i = unresolved; i; i = i->next) { namelist = alpm_list_add(namelist, (char *)alpm_pkg_get_name(i->data)); count++; @@ -306,7 +308,7 @@ void cb_question(alpm_question_t event, void *data1, void *data2, ":: The following package cannot be upgraded due to unresolvable dependencies:\n", ":: The following packages cannot be upgraded due to unresolvable dependencies:\n", count)); - list_display(" ", namelist); + list_display(" ", namelist, getcols(fileno(stdout))); printf("\n"); *response = noyes(_n( "Do you want to skip the above package for this upgrade?", @@ -317,7 +319,7 @@ void cb_question(alpm_question_t event, void *data1, void *data2, break; case ALPM_QUESTION_SELECT_PROVIDER: { - alpm_list_t *providers = (alpm_list_t *)data1; + alpm_list_t *providers = data1; size_t count = alpm_list_count(providers); char *depstring = alpm_dep_compute_string((alpm_depend_t *)data2); printf(_(":: There are %zd providers available for %s:\n"), count, @@ -340,15 +342,22 @@ void cb_question(alpm_question_t event, void *data1, void *data2, *response = yesno(_(":: File %s is corrupted (%s).\n" "Do you want to delete it?"), (char *)data1, - alpm_strerror(*(enum _alpm_errno_t *)data2)); + alpm_strerror(*(alpm_errno_t *)data2)); break; case ALPM_QUESTION_IMPORT_KEY: { alpm_pgpkey_t *key = data1; char created[12]; - strftime(created, 12, "%Y-%m-%d", localtime(&(key->created))); - *response = yesno(_(":: Import PGP key %s, \"%s\", created %s?"), - key->fingerprint, key->uid, created); + const char *revoked = ""; + time_t time = (time_t)key->created; + strftime(created, 12, "%Y-%m-%d", localtime(&time)); + + if(key->revoked) { + revoked = " (revoked)"; + } + + *response = yesno(_(":: Import PGP key %d%c/%s, \"%s\", created: %s%s?"), + key->length, key->pubkey_algo, key->fingerprint, key->uid, created, revoked); } break; } @@ -375,7 +384,7 @@ void cb_progress(alpm_progress_t event, const char *pkgname, int percent, int len, wclen, wcwid, padwid; wchar_t *wcstr; - const unsigned short cols = getcols(); + const unsigned short cols = getcols(fileno(stdout)); if(config->noprogressbar || cols == 0) { return; @@ -393,7 +402,7 @@ void cb_progress(alpm_progress_t event, const char *pkgname, int percent, if(current != prevcurrent) { /* update always */ } else if(!pkgname || percent == prevpercent || - get_update_timediff(0) < UPDATE_SPEED_SEC) { + get_update_timediff(0) < UPDATE_SPEED_MS) { /* only update the progress bar when we have a package name, the * percentage has changed, and it has been long enough. */ return; @@ -493,7 +502,7 @@ void cb_progress(alpm_progress_t event, const char *pkgname, int percent, alpm_list_t *i = NULL; on_progress = 0; for(i = output; i; i = i->next) { - printf("%s", (char *)i->data); + fputs((const char *)i->data, stdout); } fflush(stdout); FREELIST(output); @@ -528,13 +537,14 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total) int totaldownload = 0; off_t xfered, total; - double rate = 0.0, timediff = 0.0; + double rate = 0.0; + long timediff = 0; unsigned int eta_h = 0, eta_m = 0, eta_s = 0; double rate_human, xfered_human; const char *rate_label, *xfered_label; int file_percent = 0, total_percent = 0; - const unsigned short cols = getcols(); + const unsigned short cols = getcols(fileno(stdout)); if(config->noprogressbar || cols == 0 || file_total == -1) { if(file_xfered == 0) { @@ -587,16 +597,17 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total) } else if(file_xfered == file_total) { /* compute final values */ struct timeval current_time; - double diff_sec, diff_usec; + time_t diff_sec; + suseconds_t diff_usec; gettimeofday(¤t_time, NULL); 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); - if(timediff > 0.0) { - rate = xfered / timediff; - /* round elapsed time to the nearest second */ - eta_s = (unsigned int)(timediff + 0.5); + timediff = (diff_sec * 1000) + (diff_usec / 1000); + if(timediff > 0) { + rate = (double)xfered / (timediff / 1000.0); + /* round elapsed time (in ms) to the nearest second */ + eta_s = (unsigned int)(timediff + 500) / 1000; } else { eta_s = 0; } @@ -604,11 +615,11 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total) /* compute current average values */ timediff = get_update_timediff(0); - if(timediff < UPDATE_SPEED_SEC) { + if(timediff < UPDATE_SPEED_MS) { /* return if the calling interval was too short */ return; } - rate = (xfered - xfered_last) / timediff; + rate = (double)(xfered - xfered_last) / (timediff / 1000.0); /* average rate to reduce jumpiness */ rate = (rate + 2 * rate_last) / 3; if(rate > 0.0) { @@ -713,7 +724,7 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total) } else if(eta_h < 100) { printf("%02u:%02u:%02u", eta_h, eta_m, eta_s); } else { - printf("--:--"); + fputs("--:--", stdout); } free(fname); diff --git a/src/pacman/callback.h b/src/pacman/callback.h index e328a22a..2215790a 100644 --- a/src/pacman/callback.h +++ b/src/pacman/callback.h @@ -1,7 +1,7 @@ /* * callback.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify diff --git a/src/pacman/conf.c b/src/pacman/conf.c index a9f0de91..f47b92dc 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -1,7 +1,7 @@ /* * conf.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <errno.h> #include <glob.h> #include <limits.h> @@ -54,6 +52,7 @@ config_t *config_new(void) newconfig->op = PM_OP_MAIN; newconfig->logmask = ALPM_LOG_ERROR | ALPM_LOG_WARNING; newconfig->configfile = strdup(CONFFILE); + newconfig->deltaratio = 0.0; if(alpm_capabilities() & ALPM_CAPABILITY_SIGNATURES) { newconfig->siglevel = ALPM_SIG_PACKAGE | ALPM_SIG_PACKAGE_OPTIONAL | ALPM_SIG_DATABASE | ALPM_SIG_DATABASE_OPTIONAL; @@ -72,7 +71,6 @@ int config_free(config_t *oldconfig) alpm_list_free(oldconfig->explicit_removes); FREELIST(oldconfig->holdpkg); - FREELIST(oldconfig->syncfirst); FREELIST(oldconfig->ignorepkg); FREELIST(oldconfig->ignoregrp); FREELIST(oldconfig->noupgrade); @@ -203,11 +201,14 @@ static int download_with_xfercommand(const char *url, const char *localpath, cleanup: /* restore the old cwd if we have it */ if(cwdfd >= 0) { + int close_ret; if(fchdir(cwdfd) != 0) { pm_printf(ALPM_LOG_ERROR, _("could not restore working directory (%s)\n"), strerror(errno)); } - close(cwdfd); + do { + close_ret = close(cwdfd); + } while(close_ret == -1 && errno == EINTR); } if(ret == -1) { @@ -256,11 +257,11 @@ static int process_siglevel(alpm_list_t *values, alpm_siglevel_t *storage, const char *original = i->data, *value; int package = 0, database = 0; - if (strncmp(original, "Package", strlen("Package")) == 0) { + if(strncmp(original, "Package", strlen("Package")) == 0) { /* only packages are affected, don't flip flags for databases */ value = original + strlen("Package"); package = 1; - } else if (strncmp(original, "Database", strlen("Database")) == 0) { + } else if(strncmp(original, "Database", strlen("Database")) == 0) { /* only databases are affected, don't flip flags for packages */ value = original + strlen("Database"); database = 1; @@ -396,8 +397,8 @@ static int _parse_options(const char *key, char *value, config->verbosepkglists = 1; pm_printf(ALPM_LOG_DEBUG, "config: verbosepkglists\n"); } else if(strcmp(key, "UseDelta") == 0) { - config->usedelta = 1; - pm_printf(ALPM_LOG_DEBUG, "config: usedelta\n"); + config->deltaratio = 0.7; + pm_printf(ALPM_LOG_DEBUG, "config: usedelta (default 0.7)\n"); } else if(strcmp(key, "TotalDownload") == 0) { config->totaldownload = 1; pm_printf(ALPM_LOG_DEBUG, "config: totaldownload\n"); @@ -420,14 +421,24 @@ static int _parse_options(const char *key, char *value, setrepeatingoption(value, "IgnoreGroup", &(config->ignoregrp)); } else if(strcmp(key, "HoldPkg") == 0) { setrepeatingoption(value, "HoldPkg", &(config->holdpkg)); - } else if(strcmp(key, "SyncFirst") == 0) { - setrepeatingoption(value, "SyncFirst", &(config->syncfirst)); } else if(strcmp(key, "CacheDir") == 0) { setrepeatingoption(value, "CacheDir", &(config->cachedirs)); } else if(strcmp(key, "Architecture") == 0) { if(!config->arch) { config_set_arch(value); } + } else if(strcmp(key, "UseDelta") == 0) { + double ratio; + char *endptr; + ratio = strtod(value, &endptr); + if(*endptr != '\0' || ratio < 0.0 || ratio > 2.0) { + pm_printf(ALPM_LOG_ERROR, + _("config file %s, line %d: invalid value for '%s' : '%s'\n"), + file, linenum, "UseDelta", value); + return 1; + } + config->deltaratio = ratio; + pm_printf(ALPM_LOG_DEBUG, "config: usedelta = %f\n", ratio); } else if(strcmp(key, "DBPath") == 0) { /* don't overwrite a path specified on the command line */ if(!config->dbpath) { @@ -522,7 +533,7 @@ static int _add_mirror(alpm_db_t *db, char *value) static int setup_libalpm(void) { int ret = 0; - enum _alpm_errno_t err; + alpm_errno_t err; alpm_handle_t *handle; pm_printf(ALPM_LOG_DEBUG, "setup_libalpm called\n"); @@ -604,7 +615,7 @@ static int setup_libalpm(void) alpm_option_set_arch(handle, config->arch); alpm_option_set_checkspace(handle, config->checkspace); alpm_option_set_usesyslog(handle, config->usesyslog); - alpm_option_set_usedelta(handle, config->usedelta); + alpm_option_set_deltaratio(handle, config->deltaratio); alpm_option_set_ignorepkgs(handle, config->ignorepkg); alpm_option_set_ignoregroups(handle, config->ignoregrp); @@ -650,7 +661,7 @@ static int finish_section(struct section_t *section, int parse_options) } /* if we are not looking at options sections only, register a db */ - db = alpm_db_register_sync(config->handle, section->name, section->siglevel); + db = alpm_register_syncdb(config->handle, section->name, section->siglevel); if(db == NULL) { pm_printf(ALPM_LOG_ERROR, _("could not register '%s' database (%s)\n"), section->name, alpm_strerror(alpm_errno(config->handle))); @@ -659,7 +670,7 @@ static int finish_section(struct section_t *section, int parse_options) } for(i = section->servers; i; i = alpm_list_next(i)) { - char *value = alpm_list_getdata(i); + char *value = i->data; if(_add_mirror(db, value) != 0) { pm_printf(ALPM_LOG_ERROR, _("could not add mirror '%s' to database '%s' (%s)\n"), @@ -709,7 +720,8 @@ static int _parseconfig(const char *file, struct section_t *section, pm_printf(ALPM_LOG_DEBUG, "config: attempting to read file %s\n", file); fp = fopen(file, "r"); if(fp == NULL) { - pm_printf(ALPM_LOG_ERROR, _("config file %s could not be read.\n"), file); + pm_printf(ALPM_LOG_ERROR, _("config file %s could not be read: %s\n"), + file, strerror(errno)); ret = 1; goto cleanup; } @@ -725,8 +737,7 @@ static int _parseconfig(const char *file, struct section_t *section, *ptr = '\0'; } - strtrim(line); - line_len = strlen(line); + line_len = strtrim(line); if(line_len == 0) { continue; @@ -822,7 +833,7 @@ static int _parseconfig(const char *file, struct section_t *section, if((ret = _parse_options(key, value, file, linenum)) != 0) { goto cleanup; } - } else if (!parse_options && !section->is_options) { + } else if(!parse_options && !section->is_options) { /* ... or in a repo section */ if(strcmp(key, "Server") == 0) { if(value == NULL) { @@ -859,7 +870,7 @@ static int _parseconfig(const char *file, struct section_t *section, } cleanup: - if (fp) { + if(fp) { fclose(fp); } pm_printf(ALPM_LOG_DEBUG, "config: finished parsing %s\n", file); diff --git a/src/pacman/conf.h b/src/pacman/conf.h index 42f25298..69c955ed 100644 --- a/src/pacman/conf.h +++ b/src/pacman/conf.h @@ -1,7 +1,7 @@ /* * conf.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -34,7 +34,7 @@ typedef struct __config_t { unsigned short print; unsigned short checkspace; unsigned short usesyslog; - unsigned short usedelta; + double deltaratio; char *arch; char *print_format; /* unfortunately, we have to keep track of paths both here and in the library @@ -84,7 +84,6 @@ typedef struct __config_t { /* select -Sc behavior */ unsigned short cleanmethod; alpm_list_t *holdpkg; - alpm_list_t *syncfirst; alpm_list_t *ignorepkg; alpm_list_t *ignoregrp; alpm_list_t *noupgrade; @@ -127,7 +126,8 @@ enum { OP_ARCH, OP_PRINTFORMAT, OP_GPGDIR, - OP_DBONLY + OP_DBONLY, + OP_FORCE }; /* clean method */ diff --git a/src/pacman/database.c b/src/pacman/database.c index 3e4a672f..dd160135 100644 --- a/src/pacman/database.c +++ b/src/pacman/database.c @@ -1,7 +1,7 @@ /* * database.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdio.h> #include <alpm.h> @@ -63,11 +61,11 @@ int pacman_database(alpm_list_t *targets) return 1; } - db_local = alpm_option_get_localdb(config->handle); + db_local = alpm_get_localdb(config->handle); for(i = targets; i; i = alpm_list_next(i)) { char *pkgname = i->data; alpm_pkg_t *pkg = alpm_db_get_pkg(db_local, pkgname); - if(!pkg || alpm_db_set_pkgreason(config->handle, pkg, reason)) { + if(!pkg || alpm_pkg_set_reason(pkg, reason)) { pm_printf(ALPM_LOG_ERROR, _("could not set install reason for package %s (%s)\n"), pkgname, alpm_strerror(alpm_errno(config->handle))); retval = 1; diff --git a/src/pacman/deptest.c b/src/pacman/deptest.c index 0055c37e..a654c887 100644 --- a/src/pacman/deptest.c +++ b/src/pacman/deptest.c @@ -1,7 +1,7 @@ /* * deptest.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdio.h> #include <alpm.h> @@ -33,10 +31,10 @@ int pacman_deptest(alpm_list_t *targets) { alpm_list_t *i; alpm_list_t *deps = NULL; - alpm_db_t *localdb = alpm_option_get_localdb(config->handle); + alpm_db_t *localdb = alpm_get_localdb(config->handle); for(i = targets; i; i = alpm_list_next(i)) { - char *target = alpm_list_getdata(i); + char *target = i->data; if(!alpm_find_satisfier(alpm_db_get_pkgcache(localdb), target)) { deps = alpm_list_add(deps, target); @@ -48,7 +46,7 @@ int pacman_deptest(alpm_list_t *targets) } for(i = deps; i; i = alpm_list_next(i)) { - const char *dep = alpm_list_getdata(i); + const char *dep = i->data; printf("%s\n", dep); } diff --git a/src/pacman/package.c b/src/pacman/package.c index 97d89688..fe04d407 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -1,7 +1,7 @@ /* * package.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,14 +18,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <limits.h> #include <errno.h> +#include <time.h> #include <alpm.h> #include <alpm_list.h> @@ -39,17 +38,31 @@ /** Turn a depends list into a text list. * @param deps a list with items of type alpm_depend_t - * @return a string list, must be freed */ static void deplist_display(const char *title, - alpm_list_t *deps) + alpm_list_t *deps, unsigned short cols) { alpm_list_t *i, *text = NULL; for(i = deps; i; i = alpm_list_next(i)) { - alpm_depend_t *dep = alpm_list_getdata(i); + alpm_depend_t *dep = i->data; text = alpm_list_add(text, alpm_dep_compute_string(dep)); } - list_display(title, text); + list_display(title, text, cols); + FREELIST(text); +} + +/** Turn a optdepends list into a text list. + * @param optdeps a list with items of type alpm_optdepend_t + */ +static void optdeplist_display(const char *title, + alpm_list_t *optdeps, unsigned short cols) +{ + alpm_list_t *i, *text = NULL; + for(i = optdeps; i; i = alpm_list_next(i)) { + alpm_depend_t *optdep = i->data; + text = alpm_list_add(text, alpm_dep_compute_string(optdep)); + } + list_display_linebreak(title, text, cols); FREELIST(text); } @@ -63,22 +76,22 @@ static void deplist_display(const char *title, */ void dump_pkg_full(alpm_pkg_t *pkg, int extra) { - const char *reason; + unsigned short cols; time_t bdate, idate; - char bdatestr[50] = "", idatestr[50] = ""; - const char *label; - double size; - alpm_list_t *requiredby = NULL; alpm_pkgfrom_t from; + double size; + char bdatestr[50] = "", idatestr[50] = ""; + const char *label, *reason; + alpm_list_t *validation = NULL, *requiredby = NULL; from = alpm_pkg_get_origin(pkg); /* set variables here, do all output below */ - bdate = alpm_pkg_get_builddate(pkg); + bdate = (time_t)alpm_pkg_get_builddate(pkg); if(bdate) { strftime(bdatestr, 50, "%c", localtime(&bdate)); } - idate = alpm_pkg_get_installdate(pkg); + idate = (time_t)alpm_pkg_get_installdate(pkg); if(idate) { strftime(idatestr, 50, "%c", localtime(&idate)); } @@ -95,75 +108,100 @@ void dump_pkg_full(alpm_pkg_t *pkg, int extra) break; } - if(extra || from == PKG_FROM_LOCALDB) { + alpm_pkgvalidation_t v = alpm_pkg_get_validation(pkg); + if(v) { + if(v & ALPM_PKG_VALIDATION_NONE) { + validation = alpm_list_add(validation, _("None")); + } else { + if(v & ALPM_PKG_VALIDATION_MD5SUM) { + validation = alpm_list_add(validation, _("MD5 Sum")); + } + if(v & ALPM_PKG_VALIDATION_SHA256SUM) { + validation = alpm_list_add(validation, _("SHA256 Sum")); + } + if(v & ALPM_PKG_VALIDATION_SIGNATURE) { + validation = alpm_list_add(validation, _("Signature")); + } + } + } else { + validation = alpm_list_add(validation, _("Unknown")); + } + + if(extra || from == ALPM_PKG_FROM_LOCALDB) { /* compute this here so we don't get a pause in the middle of output */ requiredby = alpm_pkg_compute_requiredby(pkg); } + cols = getcols(fileno(stdout)); + /* actual output */ - if(from == PKG_FROM_SYNCDB) { + if(from == ALPM_PKG_FROM_SYNCDB) { string_display(_("Repository :"), - alpm_db_get_name(alpm_pkg_get_db(pkg))); + alpm_db_get_name(alpm_pkg_get_db(pkg)), cols); } - string_display(_("Name :"), alpm_pkg_get_name(pkg)); - string_display(_("Version :"), alpm_pkg_get_version(pkg)); - string_display(_("URL :"), alpm_pkg_get_url(pkg)); - list_display(_("Licenses :"), alpm_pkg_get_licenses(pkg)); - list_display(_("Groups :"), alpm_pkg_get_groups(pkg)); - deplist_display(_("Provides :"), alpm_pkg_get_provides(pkg)); - deplist_display(_("Depends On :"), alpm_pkg_get_depends(pkg)); - list_display_linebreak(_("Optional Deps :"), alpm_pkg_get_optdepends(pkg)); - if(extra || from == PKG_FROM_LOCALDB) { - list_display(_("Required By :"), requiredby); + string_display(_("Name :"), alpm_pkg_get_name(pkg), cols); + string_display(_("Version :"), alpm_pkg_get_version(pkg), cols); + string_display(_("URL :"), alpm_pkg_get_url(pkg), cols); + list_display(_("Licenses :"), alpm_pkg_get_licenses(pkg), cols); + list_display(_("Groups :"), alpm_pkg_get_groups(pkg), cols); + deplist_display(_("Provides :"), alpm_pkg_get_provides(pkg), cols); + deplist_display(_("Depends On :"), alpm_pkg_get_depends(pkg), cols); + optdeplist_display(_("Optional Deps :"), alpm_pkg_get_optdepends(pkg), cols); + if(extra || from == ALPM_PKG_FROM_LOCALDB) { + list_display(_("Required By :"), requiredby, cols); } - deplist_display(_("Conflicts With :"), alpm_pkg_get_conflicts(pkg)); - deplist_display(_("Replaces :"), alpm_pkg_get_replaces(pkg)); + deplist_display(_("Conflicts With :"), alpm_pkg_get_conflicts(pkg), cols); + deplist_display(_("Replaces :"), alpm_pkg_get_replaces(pkg), cols); size = humanize_size(alpm_pkg_get_size(pkg), 'K', 2, &label); - if(from == PKG_FROM_SYNCDB) { + if(from == ALPM_PKG_FROM_SYNCDB) { printf(_("Download Size : %6.2f %s\n"), size, label); - } else if(from == PKG_FROM_FILE) { + } else if(from == ALPM_PKG_FROM_FILE) { printf(_("Compressed Size: %6.2f %s\n"), size, label); } size = humanize_size(alpm_pkg_get_isize(pkg), 'K', 2, &label); printf(_("Installed Size : %6.2f %s\n"), size, label); - string_display(_("Packager :"), alpm_pkg_get_packager(pkg)); - string_display(_("Architecture :"), alpm_pkg_get_arch(pkg)); - string_display(_("Build Date :"), bdatestr); - if(from == PKG_FROM_LOCALDB) { - string_display(_("Install Date :"), idatestr); - string_display(_("Install Reason :"), reason); + string_display(_("Packager :"), alpm_pkg_get_packager(pkg), cols); + string_display(_("Architecture :"), alpm_pkg_get_arch(pkg), cols); + string_display(_("Build Date :"), bdatestr, cols); + if(from == ALPM_PKG_FROM_LOCALDB) { + string_display(_("Install Date :"), idatestr, cols); + string_display(_("Install Reason :"), reason, cols); } - if(from == PKG_FROM_FILE || from == PKG_FROM_LOCALDB) { + if(from == ALPM_PKG_FROM_FILE || from == ALPM_PKG_FROM_LOCALDB) { string_display(_("Install Script :"), - alpm_pkg_has_scriptlet(pkg) ? _("Yes") : _("No")); + alpm_pkg_has_scriptlet(pkg) ? _("Yes") : _("No"), cols); } - if(from == PKG_FROM_SYNCDB) { - string_display(_("MD5 Sum :"), alpm_pkg_get_md5sum(pkg)); - string_display(_("SHA256 Sum :"), alpm_pkg_get_sha256sum(pkg)); + if(from == ALPM_PKG_FROM_SYNCDB && extra) { + string_display(_("MD5 Sum :"), alpm_pkg_get_md5sum(pkg), cols); + string_display(_("SHA256 Sum :"), alpm_pkg_get_sha256sum(pkg), cols); string_display(_("Signatures :"), - alpm_pkg_get_base64_sig(pkg) ? _("Yes") : _("None")); + alpm_pkg_get_base64_sig(pkg) ? _("Yes") : _("None"), cols); + } else { + list_display(_("Validated By :"), validation, cols); } - if(from == PKG_FROM_FILE) { + + if(from == ALPM_PKG_FROM_FILE) { alpm_siglist_t siglist; int err = alpm_pkg_check_pgp_signature(pkg, &siglist); if(err && alpm_errno(config->handle) == ALPM_ERR_SIG_MISSING) { - string_display(_("Signatures :"), _("None")); + string_display(_("Signatures :"), _("None"), cols); } else if(err) { string_display(_("Signatures :"), - alpm_strerror(alpm_errno(config->handle))); + alpm_strerror(alpm_errno(config->handle)), cols); } else { - signature_display(_("Signatures :"), &siglist); + signature_display(_("Signatures :"), &siglist, cols); } alpm_siglist_cleanup(&siglist); } - string_display(_("Description :"), alpm_pkg_get_desc(pkg)); + + string_display(_("Description :"), alpm_pkg_get_desc(pkg), cols); /* Print additional package info if info flag passed more than once */ - if(from == PKG_FROM_LOCALDB && extra) { + if(from == ALPM_PKG_FROM_LOCALDB && extra) { dump_pkg_backups(pkg); } @@ -171,6 +209,7 @@ void dump_pkg_full(alpm_pkg_t *pkg, int extra) printf("\n"); FREELIST(requiredby); + alpm_list_free(validation); } static const char *get_backup_file_status(const char *root, @@ -223,7 +262,7 @@ void dump_pkg_backups(alpm_pkg_t *pkg) if(alpm_pkg_get_backup(pkg)) { /* package has backup files, so print them */ for(i = alpm_pkg_get_backup(pkg); i; i = alpm_list_next(i)) { - const alpm_backup_t *backup = alpm_list_getdata(i); + const alpm_backup_t *backup = i->data; const char *value; if(!backup->hash) { continue; @@ -251,11 +290,16 @@ void dump_pkg_files(alpm_pkg_t *pkg, int quiet) for(i = 0; i < pkgfiles->count; i++) { const alpm_file_t *file = pkgfiles->files + i; + /* Regular: '<pkgname> <root><filepath>\n' + * Quiet : '<root><filepath>\n' + */ if(!quiet) { - printf("%s %s%s\n", pkgname, root, file->name); - } else { - printf("%s%s\n", root, file->name); + fputs(pkgname, stdout); + putchar(' '); } + fputs(root, stdout); + fputs(file->name, stdout); + putchar('\n'); } fflush(stdout); @@ -280,10 +324,10 @@ void dump_pkg_changelog(alpm_pkg_t *pkg) /* if we hit the end of the file, we need to add a null terminator */ *(buf + ret) = '\0'; } - printf("%s", buf); + fputs(buf, stdout); } alpm_pkg_changelog_close(pkg, fp); - printf("\n"); + putchar('\n'); } } diff --git a/src/pacman/package.h b/src/pacman/package.h index 890b4fe1..1e021f4d 100644 --- a/src/pacman/package.h +++ b/src/pacman/package.h @@ -1,7 +1,7 @@ /* * package.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index c0c3bb8b..478196e2 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -1,7 +1,7 @@ /* * pacman.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - /* special handling of package version for GIT */ #if defined(GIT_VERSION) #undef PACKAGE_VERSION @@ -39,9 +37,6 @@ #include <sys/utsname.h> /* uname */ #include <locale.h> /* setlocale */ #include <errno.h> -#if defined(PACMAN_DEBUG) && defined(HAVE_MCHECK_H) -#include <mcheck.h> /* debug tracing (mtrace) */ -#endif /* alpm */ #include <alpm.h> @@ -178,7 +173,7 @@ static void usage(int op, const char * const myname) switch(op) { case PM_OP_SYNC: case PM_OP_UPGRADE: - addlist(_(" -f, --force force install, overwrite conflicting files\n")); + addlist(_(" --force force install, overwrite conflicting files\n")); addlist(_(" --asdeps install packages as non-explicitly installed\n")); addlist(_(" --asexplicit install packages as explicitly installed\n")); addlist(_(" --ignore <pkg> ignore a package upgrade (can be used more than once)\n")); @@ -208,8 +203,8 @@ static void usage(int op, const char * const myname) addlist(_(" --noconfirm do not ask for any confirmation\n")); } list = alpm_list_msort(list, alpm_list_count(list), options_cmp); - for (i = list; i; i = alpm_list_next(i)) { - printf("%s", (char *)alpm_list_getdata(i)); + for(i = list; i; i = alpm_list_next(i)) { + fputs((const char *)i->data, stdout); } alpm_list_free(list); #undef addlist @@ -528,7 +523,7 @@ static int parsearg_upgrade(int opt) if(parsearg_trans(opt) == 0) return 0; switch(opt) { - case 'f': config->flags |= ALPM_TRANS_FLAG_FORCE; break; + case OP_FORCE: config->flags |= ALPM_TRANS_FLAG_FORCE; break; case OP_ASDEPS: config->flags |= ALPM_TRANS_FLAG_ALLDEPS; break; case OP_ASEXPLICIT: config->flags |= ALPM_TRANS_FLAG_ALLEXPLICIT; break; case OP_NEEDED: config->flags |= ALPM_TRANS_FLAG_NEEDED; break; @@ -593,7 +588,6 @@ static int parseargs(int argc, char *argv[]) {"nodeps", no_argument, 0, 'd'}, {"deps", no_argument, 0, 'd'}, {"explicit", no_argument, 0, 'e'}, - {"force", no_argument, 0, 'f'}, {"groups", no_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"info", no_argument, 0, 'i'}, @@ -620,6 +614,7 @@ static int parseargs(int argc, char *argv[]) {"config", required_argument, 0, OP_CONFIG}, {"ignore", required_argument, 0, OP_IGNORE}, {"debug", optional_argument, 0, OP_DEBUG}, + {"force", no_argument, 0, OP_FORCE}, {"noprogressbar", no_argument, 0, OP_NOPROGRESSBAR}, {"noscriptlet", no_argument, 0, OP_NOSCRIPTLET}, {"ask", required_argument, 0, OP_ASK}, @@ -724,7 +719,7 @@ static int parseargs(int argc, char *argv[]) * @param argc * @param argv */ -static void cl_to_log(int argc, char* argv[]) +static void cl_to_log(int argc, char *argv[]) { size_t size = 0; int i; @@ -765,11 +760,6 @@ int main(int argc, char *argv[]) uid_t myuid = geteuid(); #endif -#if defined(PACMAN_DEBUG) && defined(HAVE_MCHECK_H) - /*setenv("MALLOC_TRACE","pacman.mtrace", 0);*/ - mtrace(); -#endif - /* Set signal handlers */ /* Set up the structure to specify the new action. */ new_action.sa_handler = handler; @@ -818,12 +808,13 @@ int main(int argc, char *argv[]) /* we support reading targets from stdin if a cmdline parameter is '-' */ if(!isatty(fileno(stdin)) && alpm_list_find_str(pm_targets, "-")) { - size_t current_size = PATH_MAX, i = 0; + size_t current_size = PATH_MAX; char *line = malloc(current_size); /* remove the '-' from the list */ pm_targets = alpm_list_remove_str(pm_targets, "-", NULL); + i = 0; while((line[i] = (char)fgetc(stdin)) != EOF) { if(isspace((unsigned char)line[i])) { /* avoid adding zero length arg when multiple spaces separate args */ @@ -895,19 +886,19 @@ int main(int argc, char *argv[]) #endif if(config->verbose > 0) { - alpm_list_t *i; + alpm_list_t *j; printf("Root : %s\n", alpm_option_get_root(config->handle)); printf("Conf File : %s\n", config->configfile); printf("DB Path : %s\n", alpm_option_get_dbpath(config->handle)); printf("Cache Dirs: "); - for(i = alpm_option_get_cachedirs(config->handle); i; i = alpm_list_next(i)) { - printf("%s ", (char *)alpm_list_getdata(i)); + for(j = alpm_option_get_cachedirs(config->handle); j; j = alpm_list_next(j)) { + printf("%s ", (const char *)j->data); } printf("\n"); printf("Lock File : %s\n", alpm_option_get_lockfile(config->handle)); printf("Log File : %s\n", alpm_option_get_logfile(config->handle)); printf("GPG Dir : %s\n", alpm_option_get_gpgdir(config->handle)); - list_display("Targets :", pm_targets); + list_display("Targets :", pm_targets, 0); } /* Log command line */ diff --git a/src/pacman/pacman.h b/src/pacman/pacman.h index 8bb9cb27..710e8fdc 100644 --- a/src/pacman/pacman.h +++ b/src/pacman/pacman.h @@ -1,7 +1,7 @@ /* * pacman.h * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify diff --git a/src/pacman/query.c b/src/pacman/query.c index ab19bab2..9b1ea6f1 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -1,7 +1,7 @@ /* * query.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <stdio.h> #include <stdint.h> @@ -38,6 +36,8 @@ #include "conf.h" #include "util.h" +#define LOCAL_PREFIX "local/" + static char *resolve_path(const char *file) { char *str = NULL; @@ -134,7 +134,7 @@ static int query_fileowner(alpm_list_t *targets) } strcpy(path, root); - db_local = alpm_option_get_localdb(config->handle); + db_local = alpm_get_localdb(config->handle); for(t = targets; t; t = alpm_list_next(t)) { char *filename, *dname, *rpath; @@ -143,7 +143,7 @@ static int query_fileowner(alpm_list_t *targets) alpm_list_t *i; int found = 0; - filename = strdup(alpm_list_getdata(t)); + filename = strdup(t->data); if(lstat(filename, &buf) == -1) { /* if it is not a path but a program name, then check in PATH */ @@ -193,7 +193,7 @@ static int query_fileowner(alpm_list_t *targets) free(dname); for(i = alpm_db_get_pkgcache(db_local); i && !found; i = alpm_list_next(i)) { - alpm_pkg_t *info = alpm_list_getdata(i); + alpm_pkg_t *info = i->data; alpm_filelist_t *filelist = alpm_pkg_get_files(info); size_t j; @@ -209,8 +209,10 @@ static int query_fileowner(alpm_list_t *targets) /* for files in '/', there is no directory name to match */ if(!rpath) { - print_query_fileowner(filename, info); - found = 1; + if(strcmp(pkgfile, bname) == 0) { + print_query_fileowner(filename, info); + found = 1; + } continue; } @@ -247,7 +249,8 @@ static int query_search(alpm_list_t *targets) { alpm_list_t *i, *searchlist; int freelist; - alpm_db_t *db_local = alpm_option_get_localdb(config->handle); + alpm_db_t *db_local = alpm_get_localdb(config->handle); + unsigned short cols; /* if we have a targets list, search for packages matching it */ if(targets) { @@ -261,37 +264,38 @@ static int query_search(alpm_list_t *targets) return 1; } + cols = getcols(fileno(stdout)); for(i = searchlist; i; i = alpm_list_next(i)) { alpm_list_t *grp; - alpm_pkg_t *pkg = alpm_list_getdata(i); + alpm_pkg_t *pkg = i->data; if(!config->quiet) { - printf("local/%s %s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); + printf(LOCAL_PREFIX "%s %s", alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); } else { - printf("%s", alpm_pkg_get_name(pkg)); + fputs(alpm_pkg_get_name(pkg), stdout); } if(!config->quiet) { if((grp = alpm_pkg_get_groups(pkg)) != NULL) { alpm_list_t *k; - printf(" ("); + fputs(" (", stdout); for(k = grp; k; k = alpm_list_next(k)) { - const char *group = alpm_list_getdata(k); - printf("%s", group); + const char *group = k->data; + fputs(group, stdout); if(alpm_list_next(k)) { /* only print a spacer if there are more groups */ - printf(" "); + putchar(' '); } } - printf(")"); + putchar(')'); } /* we need a newline and initial indent first */ - printf("\n "); - indentprint(alpm_pkg_get_desc(pkg), 4); + fputs("\n ", stdout); + indentprint(alpm_pkg_get_desc(pkg), 4, cols); } - printf("\n"); + fputc('\n', stdout); } /* we only want to free if the list was a search list */ @@ -304,33 +308,33 @@ static int query_search(alpm_list_t *targets) static int query_group(alpm_list_t *targets) { alpm_list_t *i, *j; - char *grpname = NULL; + const char *grpname = NULL; int ret = 0; - alpm_db_t *db_local = alpm_option_get_localdb(config->handle); + alpm_db_t *db_local = alpm_get_localdb(config->handle); if(targets == NULL) { for(j = alpm_db_get_groupcache(db_local); j; j = alpm_list_next(j)) { - alpm_group_t *grp = alpm_list_getdata(j); + alpm_group_t *grp = j->data; const alpm_list_t *p; for(p = grp->packages; p; p = alpm_list_next(p)) { - alpm_pkg_t *pkg = alpm_list_getdata(p); + alpm_pkg_t *pkg = p->data; printf("%s %s\n", grp->name, alpm_pkg_get_name(pkg)); } } } else { for(i = targets; i; i = alpm_list_next(i)) { alpm_group_t *grp; - grpname = alpm_list_getdata(i); - grp = alpm_db_readgroup(db_local, grpname); + grpname = i->data; + grp = alpm_db_get_group(db_local, grpname); if(grp) { const alpm_list_t *p; for(p = grp->packages; p; p = alpm_list_next(p)) { if(!config->quiet) { printf("%s %s\n", grpname, - alpm_pkg_get_name(alpm_list_getdata(p))); + alpm_pkg_get_name(p->data)); } else { - printf("%s\n", alpm_pkg_get_name(alpm_list_getdata(p))); + printf("%s\n", alpm_pkg_get_name(p->data)); } } } else { @@ -346,11 +350,11 @@ static int is_foreign(alpm_pkg_t *pkg) { const char *pkgname = alpm_pkg_get_name(pkg); alpm_list_t *j; - alpm_list_t *sync_dbs = alpm_option_get_syncdbs(config->handle); + alpm_list_t *sync_dbs = alpm_get_syncdbs(config->handle); int match = 0; for(j = sync_dbs; j; j = alpm_list_next(j)) { - alpm_db_t *db = alpm_list_getdata(j); + alpm_db_t *db = j->data; alpm_pkg_t *findpkg = alpm_db_get_pkg(db, pkgname); if(findpkg) { match = 1; @@ -395,7 +399,7 @@ static int filter(alpm_pkg_t *pkg) } /* check if this pkg is outdated */ if(config->op_q_upgrade && (alpm_sync_newversion(pkg, - alpm_option_get_syncdbs(config->handle)) == NULL)) { + alpm_get_syncdbs(config->handle)) == NULL)) { return 0; } return 1; @@ -514,7 +518,7 @@ int pacman_query(alpm_list_t *targets) } } - db_local = alpm_option_get_localdb(config->handle); + db_local = alpm_get_localdb(config->handle); /* operations on all packages in the local DB * valid: no-op (plain -Q), list, info, check @@ -526,7 +530,7 @@ int pacman_query(alpm_list_t *targets) } for(i = alpm_db_get_pkgcache(db_local); i; i = alpm_list_next(i)) { - pkg = alpm_list_getdata(i); + pkg = i->data; if(filter(pkg)) { int value = display(pkg); if(value != 0) { @@ -552,7 +556,12 @@ int pacman_query(alpm_list_t *targets) /* operations on named packages in the local DB * valid: no-op (plain -Q), list, info, check */ for(i = targets; i; i = alpm_list_next(i)) { - char *strname = alpm_list_getdata(i); + const char *strname = i->data; + + /* strip leading part of "local/pkgname" */ + if(strncmp(strname, LOCAL_PREFIX, strlen(LOCAL_PREFIX)) == 0) { + strname += strlen(LOCAL_PREFIX); + } if(config->op_q_isfile) { alpm_pkg_load(config->handle, strname, 1, 0, &pkg); diff --git a/src/pacman/remove.c b/src/pacman/remove.c index e7453c8d..472adb52 100644 --- a/src/pacman/remove.c +++ b/src/pacman/remove.c @@ -1,7 +1,7 @@ /* * remove.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,8 +18,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - +#include <fnmatch.h> #include <stdlib.h> #include <stdio.h> @@ -31,10 +30,15 @@ #include "util.h" #include "conf.h" +static int fnmatch_cmp(const void *pattern, const void *string) +{ + return fnmatch(pattern, string, 0); +} + static int remove_target(const char *target) { alpm_pkg_t *pkg; - alpm_db_t *db_local = alpm_option_get_localdb(config->handle); + alpm_db_t *db_local = alpm_get_localdb(config->handle); alpm_list_t *p; if((pkg = alpm_db_get_pkg(db_local, target)) != NULL) { @@ -48,13 +52,13 @@ static int remove_target(const char *target) } /* fallback to group */ - alpm_group_t *grp = alpm_db_readgroup(db_local, target); + alpm_group_t *grp = alpm_db_get_group(db_local, target); if(grp == NULL) { pm_printf(ALPM_LOG_ERROR, _("target not found: %s\n"), target); return -1; } for(p = grp->packages; p; p = alpm_list_next(p)) { - pkg = alpm_list_getdata(p); + pkg = p->data; if(alpm_remove_pkg(config->handle, pkg) == -1) { pm_printf(ALPM_LOG_ERROR, "'%s': %s\n", target, alpm_strerror(alpm_errno(config->handle))); @@ -89,7 +93,7 @@ int pacman_remove(alpm_list_t *targets) /* Step 1: add targets to the created transaction */ for(i = targets; i; i = alpm_list_next(i)) { - char *target = alpm_list_getdata(i); + char *target = i->data; char *targ = strchr(target, '/'); if(targ && strncmp(target, "local", 5) == 0) { targ++; @@ -98,25 +102,22 @@ int pacman_remove(alpm_list_t *targets) } if(remove_target(targ) == -1) { retval = 1; - goto cleanup; } } + if(retval == 1) { + goto cleanup; + } + /* Step 2: prepare the transaction based on its type, targets and flags */ if(alpm_trans_prepare(config->handle, &data) == -1) { - enum _alpm_errno_t err = alpm_errno(config->handle); + alpm_errno_t err = alpm_errno(config->handle); pm_printf(ALPM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), alpm_strerror(err)); switch(err) { - case ALPM_ERR_PKG_INVALID_ARCH: - for(i = data; i; i = alpm_list_next(i)) { - char *pkg = alpm_list_getdata(i); - printf(_(":: package %s does not have a valid architecture\n"), pkg); - } - break; case ALPM_ERR_UNSATISFIED_DEPS: for(i = data; i; i = alpm_list_next(i)) { - alpm_depmissing_t *miss = alpm_list_getdata(i); + alpm_depmissing_t *miss = i->data; char *depstring = alpm_dep_compute_string(miss->depend); printf(_(":: %s: requires %s\n"), miss->target, depstring); free(depstring); @@ -133,8 +134,8 @@ int pacman_remove(alpm_list_t *targets) /* Search for holdpkg in target list */ int holdpkg = 0; for(i = alpm_trans_get_remove(config->handle); i; i = alpm_list_next(i)) { - alpm_pkg_t *pkg = alpm_list_getdata(i); - if(alpm_list_find_str(config->holdpkg, alpm_pkg_get_name(pkg))) { + alpm_pkg_t *pkg = i->data; + if(alpm_list_find(config->holdpkg, alpm_pkg_get_name(pkg), fnmatch_cmp)) { pm_printf(ALPM_LOG_WARNING, _("%s is designated as a HoldPkg.\n"), alpm_pkg_get_name(pkg)); holdpkg = 1; diff --git a/src/pacman/sync.c b/src/pacman/sync.c index 951ee94c..532a6672 100644 --- a/src/pacman/sync.c +++ b/src/pacman/sync.c @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -68,7 +66,7 @@ static int sync_cleandb(const char *dbpath, int keep_used) return 1; } - syncdbs = alpm_option_get_syncdbs(config->handle); + syncdbs = alpm_get_syncdbs(config->handle); rewinddir(dir); /* step through the directory one file at a time */ @@ -118,7 +116,7 @@ static int sync_cleandb(const char *dbpath, int keep_used) if(keep_used) { alpm_list_t *i; for(i = syncdbs; i && !found; i = alpm_list_next(i)) { - alpm_db_t *db = alpm_list_getdata(i); + alpm_db_t *db = i->data; found = !strcmp(dbname, alpm_db_get_name(db)); } } @@ -169,15 +167,11 @@ static int sync_cleandb_all(void) static int sync_cleancache(int level) { alpm_list_t *i; - alpm_list_t *sync_dbs = alpm_option_get_syncdbs(config->handle); - alpm_db_t *db_local = alpm_option_get_localdb(config->handle); + alpm_list_t *sync_dbs = alpm_get_syncdbs(config->handle); + alpm_db_t *db_local = alpm_get_localdb(config->handle); alpm_list_t *cachedirs = alpm_option_get_cachedirs(config->handle); int ret = 0; - for(i = cachedirs; i; i = alpm_list_next(i)) { - printf(_("Cache directory: %s\n"), (char *)alpm_list_getdata(i)); - } - if(!config->cleanmethod) { /* default to KeepInstalled if user did not specify */ config->cleanmethod = PM_CLEAN_KEEPINST; @@ -191,22 +185,31 @@ static int sync_cleancache(int level) if(config->cleanmethod & PM_CLEAN_KEEPCUR) { printf(_(" All current sync database packages\n")); } - if(!yesno(_("Do you want to remove all other packages from cache?"))) { - return 0; - } - printf(_("removing old packages from cache...\n")); - } else { - if(!noyes(_("Do you want to remove ALL files from cache?"))) { - return 0; - } - printf(_("removing all files from cache...\n")); } + printf("\n"); for(i = cachedirs; i; i = alpm_list_next(i)) { - const char *cachedir = alpm_list_getdata(i); - DIR *dir = opendir(cachedir); + const char *cachedir = i->data; + DIR *dir; struct dirent *ent; + printf(_("Cache directory: %s\n"), (const char *)i->data); + + if(level == 1) { + if(!yesno(_("Do you want to remove all other packages from cache?"))) { + printf("\n"); + continue; + } + printf(_("removing old packages from cache...\n")); + } else { + if(!noyes(_("Do you want to remove ALL files from cache?"))) { + printf("\n"); + continue; + } + printf(_("removing all files from cache...\n")); + } + + dir = opendir(cachedir); if(dir == NULL) { pm_printf(ALPM_LOG_ERROR, _("could not access cache directory %s\n"), cachedir); @@ -226,19 +229,30 @@ static int sync_cleancache(int level) continue; } - /* skip signature files - they are removed with their package file */ - if(fnmatch("*.sig", ent->d_name, 0) == 0) { - continue; - } - - /* skip package database within the cache directory */ - if(fnmatch("*.db*", ent->d_name, 0) == 0) { - continue; - } - - /* skip source packages within the cache directory */ - if(fnmatch("*.src.tar*", ent->d_name, 0) == 0) { - continue; + if (level <= 1) { + static const char * const glob_skips[] = { + /* skip signature files - they are removed with their package file */ + "*.sig", + /* skip package database within the cache directory */ + "*.db*", + /* skip source packages within the cache directory */ + "*.src.tar.*", + /* skip package deltas, we aren't smart enough to clean these yet */ + "*.delta", + /* skip any partial downloads */ + "*.part" + }; + size_t j; + + for(j = 0; j < sizeof(glob_skips) / sizeof(glob_skips[0]); j++) { + if(fnmatch(glob_skips[j], ent->d_name, 0) == 0) { + delete = 0; + break; + } + } + if(delete == 0) { + continue; + } } /* build the full filepath */ @@ -276,7 +290,7 @@ static int sync_cleancache(int level) alpm_list_t *j; /* check if this package is in a sync DB */ for(j = sync_dbs; j && delete; j = alpm_list_next(j)) { - alpm_db_t *db = alpm_list_getdata(j); + alpm_db_t *db = j->data; pkg = alpm_db_get_pkg(db, local_name); if(pkg != NULL && alpm_pkg_vercmp(local_version, alpm_pkg_get_version(pkg)) == 0) { @@ -301,6 +315,7 @@ static int sync_cleancache(int level) } } closedir(dir); + printf("\n"); } return ret; @@ -309,12 +324,12 @@ static int sync_cleancache(int level) static int sync_synctree(int level, alpm_list_t *syncs) { alpm_list_t *i; - int success = 0, ret; + unsigned int success = 0; for(i = syncs; i; i = alpm_list_next(i)) { - alpm_db_t *db = alpm_list_getdata(i); + alpm_db_t *db = i->data; - ret = alpm_db_update((level < 2 ? 0 : 1), db); + int ret = alpm_db_update((level < 2 ? 0 : 1), db); if(ret < 0) { pm_printf(ALPM_LOG_ERROR, _("failed to update %s (%s)\n"), alpm_db_get_name(db), alpm_strerror(alpm_errno(config->handle))); @@ -358,10 +373,11 @@ static int sync_search(alpm_list_t *syncs, alpm_list_t *targets) alpm_list_t *i, *j, *ret; int freelist; int found = 0; - alpm_db_t *db_local = alpm_option_get_localdb(config->handle); + alpm_db_t *db_local = alpm_get_localdb(config->handle); for(i = syncs; i; i = alpm_list_next(i)) { - alpm_db_t *db = alpm_list_getdata(i); + alpm_db_t *db = i->data; + unsigned short cols; /* if we have a targets list, search for packages matching it */ if(targets) { ret = alpm_db_search(db, targets); @@ -375,39 +391,40 @@ static int sync_search(alpm_list_t *syncs, alpm_list_t *targets) } else { found = 1; } + cols = getcols(fileno(stdout)); for(j = ret; j; j = alpm_list_next(j)) { alpm_list_t *grp; - alpm_pkg_t *pkg = alpm_list_getdata(j); + alpm_pkg_t *pkg = j->data; if(!config->quiet) { printf("%s/%s %s", alpm_db_get_name(db), alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); } else { - printf("%s", alpm_pkg_get_name(pkg)); + fputs(alpm_pkg_get_name(pkg), stdout); } if(!config->quiet) { if((grp = alpm_pkg_get_groups(pkg)) != NULL) { alpm_list_t *k; - printf(" ("); + fputs(" (", stdout); for(k = grp; k; k = alpm_list_next(k)) { - const char *group = alpm_list_getdata(k); - printf("%s", group); + const char *group = k->data; + fputs(group, stdout); if(alpm_list_next(k)) { /* only print a spacer if there are more groups */ - printf(" "); + putchar(' '); } } - printf(")"); + putchar(')'); } print_installed(db_local, pkg); /* we need a newline and initial indent first */ - printf("\n "); - indentprint(alpm_pkg_get_desc(pkg), 4); + fputs("\n ", stdout); + indentprint(alpm_pkg_get_desc(pkg), 4, cols); } - printf("\n"); + fputc('\n', stdout); } /* we only want to free if the list was a search list */ if(freelist) { @@ -420,23 +437,23 @@ 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, *k; + alpm_list_t *i, *j, *k, *s = NULL; if(targets) { for(i = targets; i; i = alpm_list_next(i)) { - const char *grpname = alpm_list_getdata(i); + const char *grpname = i->data; for(j = syncs; j; j = alpm_list_next(j)) { - alpm_db_t *db = alpm_list_getdata(j); - alpm_group_t *grp = alpm_db_readgroup(db, grpname); + alpm_db_t *db = j->data; + alpm_group_t *grp = alpm_db_get_group(db, grpname); if(grp) { /* get names of packages in group */ for(k = grp->packages; k; k = alpm_list_next(k)) { if(!config->quiet) { printf("%s %s\n", grpname, - alpm_pkg_get_name(alpm_list_getdata(k))); + alpm_pkg_get_name(k->data)); } else { - printf("%s\n", alpm_pkg_get_name(alpm_list_getdata(k))); + printf("%s\n", alpm_pkg_get_name(k->data)); } } } @@ -444,22 +461,26 @@ static int sync_group(int level, alpm_list_t *syncs, alpm_list_t *targets) } } else { for(i = syncs; i; i = alpm_list_next(i)) { - alpm_db_t *db = alpm_list_getdata(i); + alpm_db_t *db = i->data; for(j = alpm_db_get_groupcache(db); j; j = alpm_list_next(j)) { - alpm_group_t *grp = alpm_list_getdata(j); + alpm_group_t *grp = j->data; if(level > 1) { for(k = grp->packages; k; k = alpm_list_next(k)) { printf("%s %s\n", grp->name, - alpm_pkg_get_name(alpm_list_getdata(k))); + alpm_pkg_get_name(k->data)); } } else { /* print grp names only, no package names */ - printf("%s\n", grp->name); + if(!alpm_list_find_str (s, grp->name)) { + s = alpm_list_add (s, grp->name); + printf("%s\n", grp->name); + } } } } + alpm_list_free(s); } return 0; @@ -472,7 +493,7 @@ static int sync_info(alpm_list_t *syncs, alpm_list_t *targets) if(targets) { for(i = targets; i; i = alpm_list_next(i)) { - const char *target = alpm_list_getdata(i); + const char *target = i->data; char *name = strdup(target); char *repo, *pkgstr; int foundpkg = 0, founddb = 0; @@ -488,14 +509,14 @@ static int sync_info(alpm_list_t *syncs, alpm_list_t *targets) } for(j = syncs; j; j = alpm_list_next(j)) { - alpm_db_t *db = alpm_list_getdata(j); + alpm_db_t *db = j->data; if(repo && strcmp(repo, alpm_db_get_name(db)) != 0) { continue; } founddb = 1; for(k = alpm_db_get_pkgcache(db); k; k = alpm_list_next(k)) { - alpm_pkg_t *pkg = alpm_list_getdata(k); + alpm_pkg_t *pkg = k->data; if(strcmp(alpm_pkg_get_name(pkg), pkgstr) == 0) { dump_pkg_full(pkg, config->op_s_info > 1); @@ -519,10 +540,10 @@ static int sync_info(alpm_list_t *syncs, alpm_list_t *targets) } } else { for(i = syncs; i; i = alpm_list_next(i)) { - alpm_db_t *db = alpm_list_getdata(i); + alpm_db_t *db = i->data; for(j = alpm_db_get_pkgcache(db); j; j = alpm_list_next(j)) { - alpm_pkg_t *pkg = alpm_list_getdata(j); + alpm_pkg_t *pkg = j->data; dump_pkg_full(pkg, config->op_s_info > 1); } } @@ -534,15 +555,15 @@ static int sync_info(alpm_list_t *syncs, alpm_list_t *targets) static int sync_list(alpm_list_t *syncs, alpm_list_t *targets) { alpm_list_t *i, *j, *ls = NULL; - alpm_db_t *db_local = alpm_option_get_localdb(config->handle); + alpm_db_t *db_local = alpm_get_localdb(config->handle); if(targets) { for(i = targets; i; i = alpm_list_next(i)) { - const char *repo = alpm_list_getdata(i); + const char *repo = i->data; alpm_db_t *db = NULL; for(j = syncs; j; j = alpm_list_next(j)) { - alpm_db_t *d = alpm_list_getdata(j); + alpm_db_t *d = j->data; if(strcmp(repo, alpm_db_get_name(d)) == 0) { db = d; @@ -564,10 +585,10 @@ static int sync_list(alpm_list_t *syncs, alpm_list_t *targets) } for(i = ls; i; i = alpm_list_next(i)) { - alpm_db_t *db = alpm_list_getdata(i); + alpm_db_t *db = i->data; for(j = alpm_db_get_pkgcache(db); j; j = alpm_list_next(j)) { - alpm_pkg_t *pkg = alpm_list_getdata(j); + alpm_pkg_t *pkg = j->data; if(!config->quiet) { printf("%s %s %s", alpm_db_get_name(db), alpm_pkg_get_name(pkg), @@ -587,30 +608,10 @@ static int sync_list(alpm_list_t *syncs, alpm_list_t *targets) return 0; } -static alpm_list_t *syncfirst(void) { - alpm_list_t *i, *res = NULL; - alpm_db_t *db_local = alpm_option_get_localdb(config->handle); - alpm_list_t *syncdbs = alpm_option_get_syncdbs(config->handle); - - for(i = config->syncfirst; i; i = alpm_list_next(i)) { - char *pkgname = alpm_list_getdata(i); - alpm_pkg_t *pkg = alpm_db_get_pkg(db_local, pkgname); - if(pkg == NULL) { - continue; - } - - if(alpm_sync_newversion(pkg, syncdbs)) { - res = alpm_list_add(res, strdup(pkgname)); - } - } - - return res; -} - static alpm_db_t *get_db(const char *dbname) { alpm_list_t *i; - for(i = alpm_option_get_syncdbs(config->handle); i; i = i->next) { + for(i = alpm_get_syncdbs(config->handle); i; i = i->next) { alpm_db_t *db = i->data; if(strcmp(alpm_db_get_name(db), dbname) == 0) { return db; @@ -624,7 +625,7 @@ static int process_pkg(alpm_pkg_t *pkg) int ret = alpm_add_pkg(config->handle, pkg); if(ret == -1) { - enum _alpm_errno_t err = alpm_errno(config->handle); + alpm_errno_t err = alpm_errno(config->handle); if(err == ALPM_ERR_TRANS_DUP_TARGET || err == ALPM_ERR_PKG_IGNORED) { /* just skip duplicate or ignored targets */ @@ -640,7 +641,7 @@ static int process_pkg(alpm_pkg_t *pkg) return 0; } -static int process_group(alpm_list_t *dbs, const char *group) +static int process_group(alpm_list_t *dbs, const char *group, int error) { int ret = 0; alpm_list_t *i; @@ -652,6 +653,12 @@ static int process_group(alpm_list_t *dbs, const char *group) return 1; } + if(error) { + /* we already know another target errored. there is no reason to prompt the + * user here; we already validated the group name so just move on since we + * won't actually be installing anything anyway. */ + goto cleanup; + } if(config->print == 0) { printf(_(":: There are %d members in group %s:\n"), count, @@ -671,7 +678,7 @@ static int process_group(alpm_list_t *dbs, const char *group) for(i = pkgs; i; i = alpm_list_next(i)) { if(array[n++] == 0) continue; - alpm_pkg_t *pkg = alpm_list_getdata(i); + alpm_pkg_t *pkg = i->data; if(process_pkg(pkg) == 1) { ret = 1; @@ -682,7 +689,7 @@ static int process_group(alpm_list_t *dbs, const char *group) free(array); } else { for(i = pkgs; i; i = alpm_list_next(i)) { - alpm_pkg_t *pkg = alpm_list_getdata(i); + alpm_pkg_t *pkg = i->data; if(process_pkg(pkg) == 1) { ret = 1; @@ -690,12 +697,14 @@ static int process_group(alpm_list_t *dbs, const char *group) } } } + cleanup: alpm_list_free(pkgs); return ret; } -static int process_targname(alpm_list_t *dblist, const char *targname) +static int process_targname(alpm_list_t *dblist, const char *targname, + int error) { alpm_pkg_t *pkg = alpm_find_dbs_satisfier(config->handle, dblist, targname); @@ -709,20 +718,20 @@ static int process_targname(alpm_list_t *dblist, const char *targname) return process_pkg(pkg); } /* fallback on group */ - return process_group(dblist, targname); + return process_group(dblist, targname, error); } -static int process_target(const char *target) +static int process_target(const char *target, int error) { /* process targets */ char *targstring = strdup(target); char *targname = strchr(targstring, '/'); - char *dbname = NULL; int ret = 0; - alpm_list_t *dblist = NULL; + alpm_list_t *dblist; if(targname && targname != targstring) { - alpm_db_t *db = NULL; + alpm_db_t *db; + const char *dbname; *targname = '\0'; targname++; @@ -734,14 +743,15 @@ static int process_target(const char *target) ret = 1; goto cleanup; } - dblist = alpm_list_add(dblist, db); - ret = process_targname(dblist, targname); + dblist = alpm_list_add(NULL, db); + ret = process_targname(dblist, targname, error); alpm_list_free(dblist); } else { targname = targstring; - dblist = alpm_option_get_syncdbs(config->handle); - ret = process_targname(dblist, targname); + dblist = alpm_get_syncdbs(config->handle); + ret = process_targname(dblist, targname, error); } + cleanup: free(targstring); if(ret && access(target, R_OK) == 0) { @@ -754,6 +764,7 @@ cleanup: static int sync_trans(alpm_list_t *targets) { + int retval = 0; alpm_list_t *i; /* Step 1: create a new transaction... */ @@ -763,13 +774,17 @@ static int sync_trans(alpm_list_t *targets) /* process targets */ for(i = targets; i; i = alpm_list_next(i)) { - char *targ = alpm_list_getdata(i); - if(process_target(targ) == 1) { - trans_release(); - return 1; + const char *targ = i->data; + if(process_target(targ, retval) == 1) { + retval = 1; } } + if(retval) { + trans_release(); + return retval; + } + if(config->op_s_upgrade) { printf(_(":: Starting full system upgrade...\n")); alpm_logaction(config->handle, "starting full system upgrade\n"); @@ -790,19 +805,19 @@ int sync_prepare_execute(void) /* Step 2: "compute" the transaction based on targets and flags */ if(alpm_trans_prepare(config->handle, &data) == -1) { - enum _alpm_errno_t err = alpm_errno(config->handle); + alpm_errno_t err = alpm_errno(config->handle); pm_printf(ALPM_LOG_ERROR, _("failed to prepare transaction (%s)\n"), alpm_strerror(err)); switch(err) { case ALPM_ERR_PKG_INVALID_ARCH: for(i = data; i; i = alpm_list_next(i)) { - char *pkg = alpm_list_getdata(i); + const char *pkg = i->data; printf(_(":: package %s does not have a valid architecture\n"), pkg); } break; case ALPM_ERR_UNSATISFIED_DEPS: for(i = data; i; i = alpm_list_next(i)) { - alpm_depmissing_t *miss = alpm_list_getdata(i); + alpm_depmissing_t *miss = i->data; char *depstring = alpm_dep_compute_string(miss->depend); printf(_(":: %s: requires %s\n"), miss->target, depstring); free(depstring); @@ -810,7 +825,7 @@ int sync_prepare_execute(void) break; case ALPM_ERR_CONFLICTING_DEPS: for(i = data; i; i = alpm_list_next(i)) { - alpm_conflict_t *conflict = alpm_list_getdata(i); + alpm_conflict_t *conflict = i->data; /* only print reason if it contains new information */ if(conflict->reason->mod == ALPM_DEP_MOD_ANY) { printf(_(":: %s and %s are in conflict\n"), @@ -859,13 +874,13 @@ int sync_prepare_execute(void) } if(alpm_trans_commit(config->handle, &data) == -1) { - enum _alpm_errno_t err = alpm_errno(config->handle); + alpm_errno_t err = alpm_errno(config->handle); pm_printf(ALPM_LOG_ERROR, _("failed to commit transaction (%s)\n"), alpm_strerror(err)); switch(err) { case ALPM_ERR_FILE_CONFLICTS: for(i = data; i; i = alpm_list_next(i)) { - alpm_fileconflict_t *conflict = alpm_list_getdata(i); + alpm_fileconflict_t *conflict = i->data; switch(conflict->type) { case ALPM_FILECONFLICT_TARGET: printf(_("%s exists in both '%s' and '%s'\n"), @@ -883,7 +898,7 @@ int sync_prepare_execute(void) case ALPM_ERR_PKG_INVALID_SIG: case ALPM_ERR_DLT_INVALID: for(i = data; i; i = alpm_list_next(i)) { - const char *filename = alpm_list_getdata(i); + const char *filename = i->data; printf(_("%s is invalid or corrupted\n"), filename); } break; @@ -921,7 +936,6 @@ int pacman_sync(alpm_list_t *targets) } ret += sync_cleancache(config->op_s_clean); - printf("\n"); ret += sync_cleandb_all(); if(trans_release() == -1) { @@ -935,7 +949,7 @@ int pacman_sync(alpm_list_t *targets) return 1; } - sync_dbs = alpm_option_get_syncdbs(config->handle); + sync_dbs = alpm_get_syncdbs(config->handle); if(config->op_s_sync) { /* grab a fresh package list */ @@ -983,38 +997,7 @@ int pacman_sync(alpm_list_t *targets) } } - alpm_list_t *targs = alpm_list_strdup(targets); - if(!config->op_s_downloadonly && !config->print) { - /* check for newer versions of packages to be upgraded first */ - alpm_list_t *packages = syncfirst(); - if(packages) { - /* Do not ask user if all the -S targets are SyncFirst packages, see FS#15810 */ - alpm_list_t *tmp = NULL; - if(config->op_s_upgrade || (tmp = alpm_list_diff(targets, packages, (alpm_list_fn_cmp)strcmp))) { - alpm_list_free(tmp); - printf(_(":: The following packages should be upgraded first :\n")); - list_display(" ", packages); - if(yesno(_(":: 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"); - } else { - pm_printf(ALPM_LOG_DEBUG, "skipping SyncFirst dialog\n"); - FREELIST(packages); - } - } - } - - int ret = sync_trans(targs); - FREELIST(targs); - - return ret; + return sync_trans(targets); } /* vim: set ts=2 sw=2 noet: */ diff --git a/src/pacman/upgrade.c b/src/pacman/upgrade.c index 880aa4c6..eaa36402 100644 --- a/src/pacman/upgrade.c +++ b/src/pacman/upgrade.c @@ -1,7 +1,7 @@ /* * upgrade.c * - * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org> + * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org> * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> * * This program is free software; you can redistribute it and/or modify @@ -18,8 +18,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -41,6 +39,7 @@ */ int pacman_upgrade(alpm_list_t *targets) { + int retval = 0; alpm_list_t *i; alpm_siglevel_t level = alpm_option_get_default_siglevel(config->handle); @@ -57,7 +56,7 @@ int pacman_upgrade(alpm_list_t *targets) if(str == NULL) { pm_printf(ALPM_LOG_ERROR, "'%s': %s\n", (char *)i->data, alpm_strerror(alpm_errno(config->handle))); - return 1; + retval = 1; } else { free(i->data); i->data = str; @@ -65,6 +64,10 @@ int pacman_upgrade(alpm_list_t *targets) } } + if(retval) { + return retval; + } + /* Step 1: create a new transaction */ if(trans_init(config->flags, 1) == -1) { return 1; @@ -73,25 +76,30 @@ int pacman_upgrade(alpm_list_t *targets) printf(_("loading packages...\n")); /* add targets to the created transaction */ for(i = targets; i; i = alpm_list_next(i)) { - char *targ = alpm_list_getdata(i); + const char *targ = i->data; alpm_pkg_t *pkg; if(alpm_pkg_load(config->handle, targ, 1, level, &pkg) != 0) { pm_printf(ALPM_LOG_ERROR, "'%s': %s\n", targ, alpm_strerror(alpm_errno(config->handle))); - trans_release(); - return 1; + retval = 1; + continue; } if(alpm_add_pkg(config->handle, pkg) == -1) { pm_printf(ALPM_LOG_ERROR, "'%s': %s\n", targ, alpm_strerror(alpm_errno(config->handle))); alpm_pkg_free(pkg); - trans_release(); - return 1; + retval = 1; + continue; } config->explicit_adds = alpm_list_add(config->explicit_adds, pkg); } + if(retval) { + trans_release(); + return retval; + } + /* now that targets are resolved, we can hand it all off to the sync code */ return sync_prepare_execute(); } diff --git a/src/pacman/util.c b/src/pacman/util.c index f7f8ecf5..7f7f6a74 100644 --- a/src/pacman/util.c +++ b/src/pacman/util.c @@ -18,12 +18,10 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <sys/types.h> #include <sys/ioctl.h> #include <sys/stat.h> -#include <sys/time.h> +#include <time.h> #include <stdio.h> #include <stdlib.h> @@ -65,7 +63,7 @@ int trans_init(alpm_transflag_t flags, int check_valid) void trans_init_error(void) { - enum _alpm_errno_t err = alpm_errno(config->handle); + alpm_errno_t err = alpm_errno(config->handle); pm_printf(ALPM_LOG_ERROR, _("failed to init transaction (%s)\n"), alpm_strerror(err)); if(err == ALPM_ERR_HANDLE_LOCK) { @@ -110,7 +108,7 @@ int check_syncdbs(size_t need_repos, int check_valid) { int ret = 0; alpm_list_t *i; - alpm_list_t *sync_dbs = alpm_option_get_syncdbs(config->handle); + alpm_list_t *sync_dbs = alpm_get_syncdbs(config->handle); if(need_repos && sync_dbs == NULL) { pm_printf(ALPM_LOG_ERROR, _("no usable package repositories configured.\n")); @@ -132,10 +130,10 @@ int check_syncdbs(size_t need_repos, int check_valid) } /* discard unhandled input on the terminal's input buffer */ -static int flush_term_input(void) { +static int flush_term_input(int fd) { #ifdef HAVE_TCFLUSH - if(isatty(fileno(stdin))) { - return tcflush(fileno(stdin), TCIFLUSH); + if(isatty(fd)) { + return tcflush(fd, TCIFLUSH); } #endif @@ -144,24 +142,24 @@ static int flush_term_input(void) { } /* gets the current screen column width */ -unsigned short getcols(void) +unsigned short getcols(int fd) { const unsigned short default_tty = 80; const unsigned short default_notty = 0; unsigned short termwidth = 0; - if(!isatty(fileno(stdout))) { + if(!isatty(fd)) { return default_notty; } -#ifdef TIOCGSIZE +#if defined(TIOCGSIZE) struct ttysize win; - if(ioctl(1, TIOCGSIZE, &win) == 0) { + if(ioctl(fd, TIOCGSIZE, &win) == 0) { termwidth = win.ts_cols; } #elif defined(TIOCGWINSZ) struct winsize win; - if(ioctl(1, TIOCGWINSZ, &win) == 0) { + if(ioctl(fd, TIOCGWINSZ, &win) == 0) { termwidth = win.ws_col; } #endif @@ -256,12 +254,11 @@ char *mdirname(const char *path) /* output a string, but wrap words properly with a specified indentation */ -void indentprint(const char *str, size_t indent) +void indentprint(const char *str, unsigned short indent, unsigned short cols) { wchar_t *wcstr; const wchar_t *p; - int len, cidx; - const unsigned short cols = getcols(); + size_t len, cidx; if(!str) { return; @@ -270,7 +267,7 @@ void indentprint(const char *str, size_t indent) /* if we're not a tty, or our tty is not wide enough that wrapping even makes * sense, print without indenting */ if(cols == 0 || indent > cols) { - printf("%s", str); + fputs(str, stdout); return; } @@ -318,13 +315,13 @@ void indentprint(const char *str, size_t indent) /* Trim whitespace and newlines from a string */ -char *strtrim(char *str) +size_t strtrim(char *str) { - char *pch = str; + char *end, *pch = str; if(str == NULL || *str == '\0') { /* string is empty, so we're done. */ - return str; + return 0; } while(isspace((unsigned char)*pch)) { @@ -341,16 +338,16 @@ char *strtrim(char *str) /* check if there wasn't anything but whitespace in the string. */ if(*str == '\0') { - return str; + return 0; } - pch = (str + (strlen(str) - 1)); - while(isspace((unsigned char)*pch)) { - pch--; + end = (str + strlen(str) - 1); + while(isspace((unsigned char)*end)) { + end--; } - *++pch = '\0'; + *++end = '\0'; - return str; + return end - pch; } /* Replace all occurances of 'needle' with 'replace' in 'str', returning @@ -391,7 +388,7 @@ char *strreplace(const char *str, const char *needle, const char *replace) p = str; newp = newstr; for(i = list; i; i = alpm_list_next(i)) { - q = alpm_list_getdata(i); + q = i->data; if(q > p) { /* add chars between this occurence and last occurence, if any */ memcpy(newp, p, (size_t)(q - p)); @@ -463,7 +460,7 @@ static size_t string_length(const char *s) return len; } -void string_display(const char *title, const char *string) +void string_display(const char *title, const char *string, unsigned short cols) { if(title) { printf("%s ", title); @@ -473,82 +470,128 @@ void string_display(const char *title, const char *string) } else { /* compute the length of title + a space */ size_t len = string_length(title) + 1; - indentprint(string, len); + indentprint(string, (unsigned short)len, cols); } printf("\n"); } -static void table_print_line(const alpm_list_t *line, - size_t colcount, size_t *widths) +static void table_print_line(const alpm_list_t *line, short col_padding, + size_t colcount, size_t *widths, int *has_data) { - size_t i; + size_t i, lastcol = 0; + int need_padding = 0; const alpm_list_t *curcell; + for(i = colcount; i > 0; i--) { + if(has_data[i - 1]) { + lastcol = i - 1; + break; + } + } + for(i = 0, curcell = line; curcell && i < colcount; i++, curcell = alpm_list_next(curcell)) { - const char *value = curcell->data; - size_t len = string_length(value); + const char *value; + int cell_padding; + + if(!has_data[i]) { + continue; + } + + value = curcell->data; + if(!value) { + value = ""; + } /* silly printf requires padding size to be an int */ - int padding = (int)widths[i] - (int)len; - if(padding < 0) { - padding = 0; + cell_padding = (int)widths[i] - (int)string_length(value); + if(cell_padding < 0) { + cell_padding = 0; + } + if(need_padding) { + printf("%*s", col_padding, ""); } /* left-align all but the last column */ - if(i + 1 < colcount) { - printf("%s%*s", value, padding, ""); + if(i != lastcol) { + printf("%s%*s", value, cell_padding, ""); } else { - printf("%*s%s", padding, "", value); + printf("%*s%s", cell_padding, "", value); } + need_padding = 1; } printf("\n"); } -/* find the max string width of each column */ + + +/** + * Find the max string width of each column. Also determines whether values + * exist in the column and sets the value in has_data accordingly. + * @param header a list of header strings + * @param rows a list of lists of rows as strings + * @param padding the amount of padding between columns + * @param totalcols the total number of columns in the header and each row + * @param widths a pointer to store width data + * @param has_data a pointer to store whether column has data + * + * @return the total width of the table; 0 on failure + */ static size_t table_calc_widths(const alpm_list_t *header, - const alpm_list_t *rows, size_t totalcols, size_t **widths) + const alpm_list_t *rows, short padding, size_t totalcols, + size_t **widths, int **has_data) { const alpm_list_t *i; - const unsigned short padding = 2; - size_t curcol, totalwidth = 0; + size_t curcol, totalwidth = 0, usefulcols = 0; size_t *colwidths; + int *coldata; if(totalcols <= 0) { return 0; } colwidths = malloc(totalcols * sizeof(size_t)); - if(!colwidths) { + coldata = calloc(totalcols, sizeof(int)); + if(!colwidths || !coldata) { return 0; } /* header determines column count and initial values of longest_strs */ for(i = header, curcol = 0; i; i = alpm_list_next(i), curcol++) { - colwidths[curcol] = string_length(alpm_list_getdata(i)); + colwidths[curcol] = string_length(i->data); + /* note: header does not determine whether column has data */ } /* now find the longest string in each column */ for(i = rows; i; i = alpm_list_next(i)) { /* grab first column of each row and iterate through columns */ - const alpm_list_t *j = alpm_list_getdata(i); + const alpm_list_t *j = i->data; for(curcol = 0; j; j = alpm_list_next(j), curcol++) { - char *str = alpm_list_getdata(j); + const char *str = j->data; size_t str_len = string_length(str); if(str_len > colwidths[curcol]) { colwidths[curcol] = str_len; } + if(str_len > 0) { + coldata[curcol] = 1; + } } } for(i = header, curcol = 0; i; i = alpm_list_next(i), curcol++) { - /* pad everything but the last column */ - if(curcol + 1 < totalcols) { - colwidths[curcol] += padding; + /* only include columns that have data */ + if(coldata[curcol]) { + usefulcols++; + totalwidth += colwidths[curcol]; } - totalwidth += colwidths[curcol]; + } + + /* add padding between columns */ + if(usefulcols > 0) { + totalwidth += padding * (usefulcols - 1); } *widths = colwidths; + *has_data = coldata; return totalwidth; } @@ -559,28 +602,31 @@ static size_t table_calc_widths(const alpm_list_t *header, * of headers * @param rows the rows to display as a list of lists of strings. the outer * list represents the rows, the inner list the cells (= columns) - * + * @param cols the number of columns available in the terminal * @return -1 if not enough terminal cols available, else 0 */ -int table_display(const char *title, const alpm_list_t *header, - const alpm_list_t *rows) +static int table_display(const char *title, const alpm_list_t *header, + const alpm_list_t *rows, unsigned short cols) { + const unsigned short padding = 2; const alpm_list_t *i; size_t *widths = NULL, totalcols, totalwidth; + int *has_data = NULL; if(rows == NULL || header == NULL) { return 0; } totalcols = alpm_list_count(header); - totalwidth = table_calc_widths(header, rows, totalcols, &widths); + totalwidth = table_calc_widths(header, rows, padding, totalcols, + &widths, &has_data); /* return -1 if terminal is not wide enough */ - if(totalwidth > getcols()) { + if(totalwidth > cols) { pm_printf(ALPM_LOG_WARNING, _("insufficient columns available for table display\n")); return -1; } - if(!totalwidth || !widths) { + if(!totalwidth || !widths || !has_data) { return -1; } @@ -588,18 +634,20 @@ int table_display(const char *title, const alpm_list_t *header, printf("%s\n\n", title); } - table_print_line(header, totalcols, widths); + table_print_line(header, padding, totalcols, widths, has_data); printf("\n"); for(i = rows; i; i = alpm_list_next(i)) { - table_print_line(alpm_list_getdata(i), totalcols, widths); + table_print_line(i->data, padding, totalcols, widths, has_data); } free(widths); + free(has_data); return 0; } -void list_display(const char *title, const alpm_list_t *list) +void list_display(const char *title, const alpm_list_t *list, + unsigned short maxcols) { const alpm_list_t *i; size_t len = 0; @@ -612,20 +660,19 @@ void list_display(const char *title, const alpm_list_t *list) if(!list) { printf("%s\n", _("None")); } else { - const unsigned short maxcols = getcols(); size_t cols = len; - const char *str = alpm_list_getdata(list); - printf("%s", str); + const char *str = list->data; + fputs(str, stdout); cols += string_length(str); for(i = alpm_list_next(list); i; i = alpm_list_next(i)) { - str = alpm_list_getdata(i); + str = i->data; size_t s = string_length(str); /* wrap only if we have enough usable column space */ if(maxcols > len && cols + s + 2 >= maxcols) { size_t j; cols = len; printf("\n"); - for (j = 1; j <= len; j++) { + for(j = 1; j <= len; j++) { printf(" "); } } else if(cols != len) { @@ -633,19 +680,20 @@ void list_display(const char *title, const alpm_list_t *list) printf(" "); cols += 2; } - printf("%s", str); + fputs(str, stdout); cols += s; } - printf("\n"); + putchar('\n'); } } -void list_display_linebreak(const char *title, const alpm_list_t *list) +void list_display_linebreak(const char *title, const alpm_list_t *list, + unsigned short maxcols) { - size_t len = 0; + unsigned short len = 0; if(title) { - len = string_length(title) + 1; + len = (unsigned short)string_length(title) + 1; printf("%s ", title); } @@ -654,7 +702,7 @@ void list_display_linebreak(const char *title, const alpm_list_t *list) } else { const alpm_list_t *i; /* Print the first element */ - indentprint((const char *) alpm_list_getdata(list), len); + indentprint((const char *)list->data, len, maxcols); printf("\n"); /* Print the rest */ for(i = alpm_list_next(list); i; i = alpm_list_next(i)) { @@ -662,18 +710,19 @@ void list_display_linebreak(const char *title, const alpm_list_t *list) for(j = 1; j <= len; j++) { printf(" "); } - indentprint((const char *) alpm_list_getdata(i), len); + indentprint((const char *)i->data, len, maxcols); printf("\n"); } } } -void signature_display(const char *title, alpm_siglist_t *siglist) +void signature_display(const char *title, alpm_siglist_t *siglist, + unsigned short maxcols) { - size_t len = 0; + unsigned short len = 0; if(title) { - len = string_length(title) + 1; + len = (unsigned short)string_length(title) + 1; printf("%s ", title); } if(siglist->count == 0) { @@ -737,7 +786,7 @@ void signature_display(const char *title, alpm_siglist_t *siglist) pm_printf(ALPM_LOG_ERROR, _("failed to allocate string\n")); continue; } - indentprint(sigline, len); + indentprint(sigline, len, maxcols); printf("\n"); free(sigline); } @@ -745,7 +794,7 @@ void signature_display(const char *title, alpm_siglist_t *siglist) } /* creates a header row for use with table_display */ -static alpm_list_t *create_verbose_header(int dl_size) +static alpm_list_t *create_verbose_header(void) { alpm_list_t *res = NULL; char *str; @@ -758,16 +807,14 @@ static alpm_list_t *create_verbose_header(int dl_size) res = alpm_list_add(res, str); str = _("Net Change"); res = alpm_list_add(res, str); - if(dl_size) { - str = _("Download Size"); - res = alpm_list_add(res, str); - } + str = _("Download Size"); + res = alpm_list_add(res, str); return res; } /* returns package info as list of strings */ -static alpm_list_t *create_verbose_row(pm_target_t *target, int dl_size) +static alpm_list_t *create_verbose_row(pm_target_t *target) { char *str; off_t size = 0; @@ -777,7 +824,12 @@ static alpm_list_t *create_verbose_row(pm_target_t *target, int dl_size) /* a row consists of the package name, */ if(target->install) { - pm_asprintf(&str, "%s", alpm_pkg_get_name(target->install)); + const alpm_db_t *db = alpm_pkg_get_db(target->install); + if(db) { + pm_asprintf(&str, "%s/%s", alpm_db_get_name(db), alpm_pkg_get_name(target->install)); + } else { + pm_asprintf(&str, "%s", alpm_pkg_get_name(target->install)); + } } else { pm_asprintf(&str, "%s", alpm_pkg_get_name(target->remove)); } @@ -799,16 +851,14 @@ static alpm_list_t *create_verbose_row(pm_target_t *target, int dl_size) pm_asprintf(&str, "%.2f %s", human_size, label); ret = alpm_list_add(ret, str); - if(dl_size) { - size = target->install ? alpm_pkg_download_size(target->install) : 0; + size = target->install ? alpm_pkg_download_size(target->install) : 0; + if(size != 0) { human_size = humanize_size(size, 'M', 2, &label); - if(size != 0) { - pm_asprintf(&str, "%.2f %s", human_size, label); - } else { - str = strdup(""); - } - ret = alpm_list_add(ret, str); + pm_asprintf(&str, "%.2f %s", human_size, label); + } else { + str = NULL; } + ret = alpm_list_add(ret, str); return ret; } @@ -820,8 +870,8 @@ static void _display_targets(alpm_list_t *targets, int verbose) const char *label; double size; off_t isize = 0, rsize = 0, dlsize = 0; + unsigned short cols; alpm_list_t *i, *rows = NULL, *names = NULL; - int show_dl_size = config->op == PM_OP_SYNC; if(!targets) { return; @@ -829,7 +879,7 @@ static void _display_targets(alpm_list_t *targets, int verbose) /* gather package info */ for(i = targets; i; i = alpm_list_next(i)) { - pm_target_t *target = alpm_list_getdata(i); + pm_target_t *target = i->data; if(target->install) { dlsize += alpm_pkg_download_size(target->install); @@ -845,7 +895,7 @@ static void _display_targets(alpm_list_t *targets, int verbose) for(i = targets; i; i = alpm_list_next(i)) { pm_target_t *target = i->data; - rows = alpm_list_add(rows, create_verbose_row(target, show_dl_size)); + rows = alpm_list_add(rows, create_verbose_row(target)); if(target->install) { pm_asprintf(&str, "%s-%s", alpm_pkg_get_name(target->install), alpm_pkg_get_version(target->install)); @@ -860,24 +910,25 @@ static void _display_targets(alpm_list_t *targets, int verbose) } /* print to screen */ - pm_asprintf(&str, _("Targets (%d):"), alpm_list_count(targets)); - + pm_asprintf(&str, _("Packages (%d):"), alpm_list_count(targets)); printf("\n"); + + cols = getcols(fileno(stdout)); if(verbose) { - alpm_list_t *header = create_verbose_header(show_dl_size); - if(table_display(str, header, rows) != 0) { + alpm_list_t *header = create_verbose_header(); + if(table_display(str, header, rows, cols) != 0) { /* fallback to list display if table wouldn't fit */ - list_display(str, names); + list_display(str, names, cols); } alpm_list_free(header); } else { - list_display(str, names); + list_display(str, names, cols); } printf("\n"); /* rows is a list of lists of strings, free inner lists here */ for(i = rows; i; i = alpm_list_next(i)) { - alpm_list_t *lp = alpm_list_getdata(i); + alpm_list_t *lp = i->data; FREELIST(lp); } alpm_list_free(rows); @@ -931,10 +982,10 @@ static int pkg_cmp(const void *p1, const void *p2) void display_targets(void) { alpm_list_t *i, *targets = NULL; - alpm_db_t *db_local = alpm_option_get_localdb(config->handle); + alpm_db_t *db_local = alpm_get_localdb(config->handle); for(i = alpm_trans_get_add(config->handle); i; i = alpm_list_next(i)) { - alpm_pkg_t *pkg = alpm_list_getdata(i); + alpm_pkg_t *pkg = i->data; pm_target_t *targ = calloc(1, sizeof(pm_target_t)); if(!targ) return; targ->install = pkg; @@ -945,7 +996,7 @@ void display_targets(void) targets = alpm_list_add(targets, targ); } for(i = alpm_trans_get_remove(config->handle); i; i = alpm_list_next(i)) { - alpm_pkg_t *pkg = alpm_list_getdata(i); + alpm_pkg_t *pkg = i->data; pm_target_t *targ = calloc(1, sizeof(pm_target_t)); if(!targ) return; targ->remove = pkg; @@ -980,7 +1031,7 @@ static char *pkg_get_location(alpm_pkg_t *pkg) case PM_OP_SYNC: servers = alpm_db_get_servers(alpm_pkg_get_db(pkg)); if(servers) { - pm_asprintf(&string, "%s/%s", alpm_list_getdata(servers), + pm_asprintf(&string, "%s/%s", servers->data, alpm_pkg_get_filename(pkg)); return string; } @@ -1054,7 +1105,7 @@ void print_packages(const alpm_list_t *packages) config->print_format = strdup("%l"); } for(i = packages; i; i = alpm_list_next(i)) { - alpm_pkg_t *pkg = alpm_list_getdata(i); + alpm_pkg_t *pkg = i->data; char *string = strdup(config->print_format); char *temp = string; /* %n : pkgname */ @@ -1096,46 +1147,104 @@ void print_packages(const alpm_list_t *packages) free(size); free(temp); } - printf("%s\n",string); + printf("%s\n", string); free(string); } } -/* Helper function for comparing strings using the - * alpm "compare func" signature */ -int str_cmp(const void *s1, const void *s2) +/** + * Helper function for comparing depends using the alpm "compare func" + * signature. The function descends through the structure in the following + * comparison order: name, modifier (e.g., '>', '='), version, description. + * @param d1 the first depend structure + * @param d2 the second depend structure + * @return -1, 0, or 1 if first is <, ==, or > second + */ +static int depend_cmp(const void *d1, const void *d2) { - return strcmp(s1, s2); + const alpm_depend_t *dep1 = d1; + const alpm_depend_t *dep2 = d2; + int ret; + + ret = strcmp(dep1->name, dep2->name); + if(ret == 0) { + ret = dep1->mod - dep2->mod; + } + if(ret == 0) { + if(dep1->version && dep2->version) { + ret = strcmp(dep1->version, dep2->version); + } else if(!dep1->version && dep2->version) { + ret = -1; + } else if(dep1->version && !dep2->version) { + ret = 1; + } + } + if(ret == 0) { + if(dep1->desc && dep2->desc) { + ret = strcmp(dep1->desc, dep2->desc); + } else if(!dep1->desc && dep2->desc) { + ret = -1; + } else if(dep1->desc && !dep2->desc) { + ret = 1; + } + } + + return ret; } void display_new_optdepends(alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg) { - alpm_list_t *old = alpm_pkg_get_optdepends(oldpkg); - alpm_list_t *new = alpm_pkg_get_optdepends(newpkg); - alpm_list_t *optdeps = alpm_list_diff(new,old,str_cmp); - if(optdeps) { + alpm_list_t *i, *old, *new, *optdeps, *optstrings = NULL; + + old = alpm_pkg_get_optdepends(oldpkg); + new = alpm_pkg_get_optdepends(newpkg); + optdeps = alpm_list_diff(new, old, depend_cmp); + + /* turn optdepends list into a text list */ + for(i = optdeps; i; i = alpm_list_next(i)) { + alpm_depend_t *optdep = i->data; + optstrings = alpm_list_add(optstrings, alpm_dep_compute_string(optdep)); + } + + if(optstrings) { printf(_("New optional dependencies for %s\n"), alpm_pkg_get_name(newpkg)); - list_display_linebreak(" ", optdeps); + unsigned short cols = getcols(fileno(stdout)); + list_display_linebreak(" ", optstrings, cols); } + alpm_list_free(optdeps); + FREELIST(optstrings); } void display_optdepends(alpm_pkg_t *pkg) { - alpm_list_t *optdeps = alpm_pkg_get_optdepends(pkg); - if(optdeps) { + alpm_list_t *i, *optdeps, *optstrings = NULL; + + optdeps = alpm_pkg_get_optdepends(pkg); + + /* turn optdepends list into a text list */ + for(i = optdeps; i; i = alpm_list_next(i)) { + alpm_depend_t *optdep = i->data; + optstrings = alpm_list_add(optstrings, alpm_dep_compute_string(optdep)); + } + + if(optstrings) { printf(_("Optional dependencies for %s\n"), alpm_pkg_get_name(pkg)); - list_display_linebreak(" ", optdeps); + unsigned short cols = getcols(fileno(stdout)); + list_display_linebreak(" ", optstrings, cols); } + + FREELIST(optstrings); } -static void display_repo_list(const char *dbname, alpm_list_t *list) +static void display_repo_list(const char *dbname, alpm_list_t *list, + unsigned short cols) { const char *prefix= " "; printf(":: "); printf(_("Repository %s\n"), dbname); - list_display(prefix, list); + list_display(prefix, list, cols); } void select_display(const alpm_list_t *pkglist) @@ -1145,15 +1254,16 @@ void select_display(const alpm_list_t *pkglist) alpm_list_t *list = NULL; char *string = NULL; const char *dbname = NULL; + unsigned short cols = getcols(fileno(stdout)); - for (i = pkglist; i; i = i->next) { - alpm_pkg_t *pkg = alpm_list_getdata(i); + for(i = pkglist; i; i = i->next) { + alpm_pkg_t *pkg = i->data; alpm_db_t *db = alpm_pkg_get_db(pkg); if(!dbname) dbname = alpm_db_get_name(db); if(strcmp(alpm_db_get_name(db), dbname) != 0) { - display_repo_list(dbname, list); + display_repo_list(dbname, list, cols); FREELIST(list); dbname = alpm_db_get_name(db); } @@ -1162,7 +1272,7 @@ void select_display(const alpm_list_t *pkglist) list = alpm_list_add(list, string); nth++; } - display_repo_list(dbname, list); + display_repo_list(dbname, list, cols); FREELIST(list); } @@ -1189,17 +1299,17 @@ static int multiselect_parse(char *array, int count, char *response) { char *str, *saveptr; - for (str = response; ; str = NULL) { + for(str = response; ; str = NULL) { int include = 1; int start, end; + size_t len; char *ends = NULL; - char *starts = strtok_r(str, " ", &saveptr); + char *starts = strtok_r(str, " ,", &saveptr); if(starts == NULL) { break; } - strtrim(starts); - int len = strlen(starts); + len = strtrim(starts); if(len == 0) continue; @@ -1274,10 +1384,11 @@ int multiselect_question(char *array, int count) break; } - flush_term_input(); + flush_term_input(fileno(stdin)); if(fgets(response, response_len, stdin)) { const size_t response_incr = 64; + size_t len; /* handle buffer not being large enough to read full line case */ while(*lastchar == '\0' && lastchar[-1] != '\n') { response_len += response_incr; @@ -1294,8 +1405,9 @@ int multiselect_question(char *array, int count) return -1; } } - strtrim(response); - if(strlen(response) > 0) { + + len = strtrim(response); + if(len > 0) { if(multiselect_parse(array, count, response) == -1) { /* only loop if user gave an invalid answer */ continue; @@ -1335,11 +1447,11 @@ int select_question(int count) break; } - flush_term_input(); + flush_term_input(fileno(stdin)); if(fgets(response, sizeof(response), stdin)) { - strtrim(response); - if(strlen(response) > 0) { + size_t len = strtrim(response); + if(len > 0) { int n; if(parseindex(response, &n, 1, count) != 0) continue; @@ -1358,6 +1470,7 @@ static int question(short preset, char *fmt, va_list args) { char response[32]; FILE *stream; + int fd_in = fileno(stdin); if(config->noconfirm) { stream = stdout; @@ -1384,17 +1497,17 @@ static int question(short preset, char *fmt, va_list args) } fflush(stream); - flush_term_input(); + flush_term_input(fd_in); if(fgets(response, sizeof(response), stdin)) { - strtrim(response); - if(strlen(response) == 0) { + size_t len = strtrim(response); + if(len == 0) { return preset; } /* if stdin is piped, response does not get printed out, and as a result * a \n is missing, resulting in broken output (FS#27909) */ - if(!isatty(fileno(stdin))) { + if(!isatty(fd_in)) { fprintf(stream, "%s\n", response); } diff --git a/src/pacman/util.h b/src/pacman/util.h index 5ccd480a..0dfdc851 100644 --- a/src/pacman/util.h +++ b/src/pacman/util.h @@ -36,9 +36,6 @@ #define _n(str1, str2, ct) (ct == 1 ? str1 : str2) #endif -/* update speed for the fill_progress based functions */ -#define UPDATE_SPEED_SEC 0.2f - typedef struct _pm_target_t { alpm_pkg_t *remove; alpm_pkg_t *install; @@ -50,21 +47,23 @@ int trans_init(alpm_transflag_t flags, int check_valid); int trans_release(void); int needs_root(void); int check_syncdbs(size_t need_repos, int check_valid); -unsigned short getcols(void); +unsigned short getcols(int fd); int rmrf(const char *path); const char *mbasename(const char *path); char *mdirname(const char *path); -void indentprint(const char *str, size_t indent); -char *strtrim(char *str); +void indentprint(const char *str, unsigned short indent, unsigned short cols); +size_t strtrim(char *str); char *strreplace(const char *str, const char *needle, const char *replace); alpm_list_t *strsplit(const char *str, const char splitchar); -void string_display(const char *title, const char *string); +void string_display(const char *title, const char *string, unsigned short cols); double humanize_size(off_t bytes, const char target_unit, int precision, const char **label); -int table_display(const char *title, const alpm_list_t *header, const alpm_list_t *rows); -void list_display(const char *title, const alpm_list_t *list); -void list_display_linebreak(const char *title, const alpm_list_t *list); -void signature_display(const char *title, alpm_siglist_t *siglist); +void list_display(const char *title, const alpm_list_t *list, + unsigned short maxcols); +void list_display_linebreak(const char *title, const alpm_list_t *list, + unsigned short maxcols); +void signature_display(const char *title, alpm_siglist_t *siglist, + unsigned short maxcols); void display_targets(void); int str_cmp(const void *s1, const void *s2); void display_new_optdepends(alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg); diff --git a/src/util/Makefile.am b/src/util/Makefile.am index e4af56cf..463abf7f 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -1,19 +1,23 @@ # paths set at make time conffile = ${sysconfdir}/pacman.conf dbpath = ${localstatedir}/lib/pacman/ +gpgdir = ${sysconfdir}/pacman.d/gnupg/ cachedir = ${localstatedir}/cache/pacman/pkg/ bin_PROGRAMS = vercmp testpkg testdb cleanupdelta pacsort pactree DEFS = -DLOCALEDIR=\"@localedir@\" \ -DCONFFILE=\"$(conffile)\" \ - -DROOTDIR=\"$(ROOTDIR)\" \ -DDBPATH=\"$(dbpath)\" \ + -DGPGDIR=\"$(gpgdir)\" \ -DCACHEDIR=\"$(cachedir)\" \ @DEFS@ -INCLUDES = -I$(top_srcdir)/lib/libalpm -AM_CFLAGS = -pedantic -D_GNU_SOURCE +AM_CPPFLAGS = \ + -imacros $(top_builddir)/config.h \ + -I$(top_srcdir)/lib/libalpm + +AM_CFLAGS = -pedantic -D_GNU_SOURCE $(WARNING_CFLAGS) cleanupdelta_SOURCES = cleanupdelta.c cleanupdelta_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la @@ -31,6 +35,6 @@ testpkg_SOURCES = testpkg.c testpkg_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la vercmp_SOURCES = vercmp.c -vercmp_LDADD = $(top_builddir)/lib/libalpm/version.lo +vercmp_LDADD = $(top_builddir)/lib/libalpm/libalpm_la-version.lo # vim:set ts=2 sw=2 noet: diff --git a/src/util/cleanupdelta.c b/src/util/cleanupdelta.c index 6553e6f6..2f7720b5 100644 --- a/src/util/cleanupdelta.c +++ b/src/util/cleanupdelta.c @@ -17,8 +17,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -56,10 +54,10 @@ static void checkpkgs(alpm_list_t *pkglist) { alpm_list_t *i, *j; for(i = pkglist; i; i = alpm_list_next(i)) { - alpm_pkg_t *pkg = alpm_list_getdata(i); + alpm_pkg_t *pkg = i->data; alpm_list_t *unused = alpm_pkg_unused_deltas(pkg); for(j = unused; j; j = alpm_list_next(j)) { - char *delta = alpm_list_getdata(j); + const char *delta = j->data; printf("%s\n", delta); } alpm_list_free(unused); @@ -72,8 +70,8 @@ static void checkdbs(alpm_list_t *dbnames) { const alpm_siglevel_t level = ALPM_SIG_DATABASE | ALPM_SIG_DATABASE_OPTIONAL; for(i = dbnames; i; i = alpm_list_next(i)) { - const char *dbname = alpm_list_getdata(i); - db = alpm_db_register_sync(handle, dbname, level); + const char *dbname = i->data; + db = alpm_register_syncdb(handle, dbname, level); if(db == NULL) { fprintf(stderr, "error: could not register sync database '%s' (%s)\n", dbname, alpm_strerror(alpm_errno(handle))); @@ -94,7 +92,7 @@ static void usage(void) { int main(int argc, char *argv[]) { const char *dbpath = DBPATH; - enum _alpm_errno_t err; + alpm_errno_t err; int a = 1; alpm_list_t *dbnames = NULL; diff --git a/src/util/pacsort.c b/src/util/pacsort.c index 0eedf59d..7275cc77 100644 --- a/src/util/pacsort.c +++ b/src/util/pacsort.c @@ -17,8 +17,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <errno.h> #include <getopt.h> #include <stdio.h> diff --git a/src/util/pactree.c b/src/util/pactree.c index cee5433a..4488645f 100644 --- a/src/util/pactree.c +++ b/src/util/pactree.c @@ -17,8 +17,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <ctype.h> #include <getopt.h> #include <stdio.h> @@ -29,11 +27,18 @@ #define LINE_MAX 512 +typedef struct tdepth { + struct tdepth *prev; + struct tdepth *next; + int level; +} tdepth; + /* output */ struct graph_style { const char *provides; const char *tip1; const char *tip2; + const char *limb; int indent; }; @@ -41,6 +46,7 @@ static struct graph_style graph_default = { " provides", "|--", "+--", + "|", 3 }; @@ -48,6 +54,7 @@ static struct graph_style graph_linear = { "", "", "", + "", 0 }; @@ -119,13 +126,13 @@ char *strndup(const char *s, size_t n) } #endif -static char *strtrim(char *str) +static size_t strtrim(char *str) { - char *pch = str; + char *end, *pch = str; if(str == NULL || *str == '\0') { /* string is empty, so we're done. */ - return str; + return 0; } while(isspace((unsigned char)*pch)) { @@ -142,21 +149,21 @@ static char *strtrim(char *str) /* check if there wasn't anything but whitespace in the string. */ if(*str == '\0') { - return str; + return 0; } - pch = (str + (strlen(str) - 1)); - while(isspace((unsigned char)*pch)) { - pch--; + end = (str + strlen(str) - 1); + while(isspace((unsigned char)*end)) { + end--; } - *++pch = '\0'; + *++end = '\0'; - return str; + return end - pch; } static int register_syncs(void) { FILE *fp; - char *ptr, *section = NULL; + char *section = NULL; char line[LINE_MAX]; const alpm_siglevel_t level = ALPM_SIG_DATABASE | ALPM_SIG_DATABASE_OPTIONAL; @@ -167,23 +174,26 @@ static int register_syncs(void) { } while(fgets(line, LINE_MAX, fp)) { + size_t linelen; + char *ptr; + /* ignore whole line and end of line comments */ if((ptr = strchr(line, '#'))) { *ptr = '\0'; } - strtrim(line); + linelen = strtrim(line); - if(strlen(line) == 0) { + if(linelen == 0) { continue; } - if(line[0] == '[' && line[strlen(line) - 1] == ']') { + if(line[0] == '[' && line[linelen - 1] == ']') { free(section); - section = strndup(&line[1], strlen(line) - 2); + section = strndup(&line[1], linelen - 2); if(section && strcmp(section, "options") != 0) { - alpm_db_register_sync(handle, section, level); + alpm_register_syncdb(handle, section, level); } } } @@ -291,28 +301,36 @@ static void cleanup(void) } /* pkg provides provision */ -static void print_text(const char *pkg, const char *provision, int depth) +static void print_text(const char *pkg, const char *provision, tdepth *depth) { - int indent_sz = (depth + 1) * style->indent; - if(!pkg && !provision) { /* not much we can do */ return; } + /* print limbs */ + while(depth->prev) + depth = depth->prev; + int level = 0; + printf("%s", color->branch1); + while(depth->next){ + printf("%*s%-*s", style->indent * (depth->level - level), "", + style->indent, style->limb); + level = depth->level + 1; + depth = depth->next; + } + printf("%*s", style->indent * (depth->level - level), ""); + + /* print tip */ if(!pkg && provision) { - /* we failed to resolve provision */ - printf("%s%*s%s%s%s [unresolvable]%s\n", color->branch1, indent_sz, - style->tip1, color->leaf1, provision, color->branch1, color->off); + printf("%s%s%s%s [unresolvable]%s\n", style->tip1, color->leaf1, + provision, color->branch1, color->off); } else if(provision && strcmp(pkg, provision) != 0) { - /* pkg provides provision */ - printf("%s%*s%s%s%s%s %s%s%s\n", color->branch2, indent_sz, style->tip2, - color->leaf1, pkg, color->leaf2, style->provides, color->leaf1, provision, + printf("%s%s%s%s%s %s%s%s\n", style->tip2, color->leaf1, pkg, + color->leaf2, style->provides, color->leaf1, provision, color->off); } else { - /* pkg is a normal package */ - printf("%s%*s%s%s%s\n", color->branch1, indent_sz, style->tip1, color->leaf1, - pkg, color->off); + printf("%s%s%s%s\n", style->tip1, color->leaf1, pkg, color->off); } } @@ -330,7 +348,7 @@ static void print_graph(const char *parentname, const char *pkgname, const char } /* parent depends on dep which is satisfied by pkg */ -static void print(const char *parentname, const char *pkgname, const char *depname, int depth) +static void print(const char *parentname, const char *pkgname, const char *depname, tdepth *depth) { if(graphviz) { print_graph(parentname, pkgname, depname); @@ -346,7 +364,12 @@ static void print_start(const char *pkgname, const char *provname) "node [style=filled, color=green];\n" " \"START\" -> \"%s\";\n", pkgname); } else { - print_text(pkgname, provname, 0); + tdepth d = { + NULL, + NULL, + 0 + }; + print_text(pkgname, provname, &d); } } @@ -358,92 +381,80 @@ static void print_end(void) } } -static alpm_pkg_t *get_pkg_from_dbs(alpm_list_t *dbs, const char *needle) { - alpm_list_t *i; - alpm_pkg_t *ret; - - for(i = dbs; i; i = alpm_list_next(i)) { - ret = alpm_db_get_pkg(alpm_list_getdata(i), needle); - if(ret) { - return ret; - } +static alpm_list_t *get_pkg_dep_names(alpm_pkg_t *pkg) +{ + alpm_list_t *i, *names = NULL; + for(i = alpm_pkg_get_depends(pkg); i; i = alpm_list_next(i)) { + alpm_depend_t *d = i->data; + names = alpm_list_add(names, d->name); } - return NULL; + return names; } /** - * walk dependencies in reverse, showing packages which require the target + * walk dependencies, showing dependencies of the target */ -static void walk_reverse_deps(alpm_list_t *dblist, alpm_pkg_t *pkg, int depth) +static void walk_deps(alpm_list_t *dblist, alpm_pkg_t *pkg, tdepth *depth, int rev) { - alpm_list_t *required_by, *i; + alpm_list_t *deps, *i; - if(!pkg || ((max_depth >= 0) && (depth == max_depth + 1))) { + if(!pkg || ((max_depth >= 0) && (depth->level > max_depth))) { return; } walked = alpm_list_add(walked, (void *)alpm_pkg_get_name(pkg)); - required_by = alpm_pkg_compute_requiredby(pkg); - for(i = required_by; i; i = alpm_list_next(i)) { - const char *pkgname = alpm_list_getdata(i); + if(rev) { + deps = alpm_pkg_compute_requiredby(pkg); + } else { + deps = get_pkg_dep_names(pkg); + } + + for(i = deps; i; i = alpm_list_next(i)) { + const char *pkgname = i->data; - if(alpm_list_find_str(walked, pkgname)) { + alpm_pkg_t *dep_pkg = alpm_find_dbs_satisfier(handle, dblist, pkgname); + + if(alpm_list_find_str(walked, dep_pkg ? alpm_pkg_get_name(dep_pkg) : pkgname)) { /* if we've already seen this package, don't print in "unique" output * and don't recurse */ if(!unique) { - print(alpm_pkg_get_name(pkg), pkgname, NULL, depth); + print(alpm_pkg_get_name(pkg), alpm_pkg_get_name(dep_pkg), pkgname, depth); } } else { - print(alpm_pkg_get_name(pkg), pkgname, NULL, depth); - walk_reverse_deps(dblist, get_pkg_from_dbs(dblist, pkgname), depth + 1); - } - } - - FREELIST(required_by); -} - -/** - * walk dependencies, showing dependencies of the target - */ -static void walk_deps(alpm_list_t *dblist, alpm_pkg_t *pkg, int depth) -{ - alpm_list_t *i; - - if((max_depth >= 0) && (depth == max_depth + 1)) { - return; - } - - walked = alpm_list_add(walked, (void *)alpm_pkg_get_name(pkg)); - - for(i = alpm_pkg_get_depends(pkg); i; i = alpm_list_next(i)) { - alpm_depend_t *depend = alpm_list_getdata(i); - alpm_pkg_t *provider = alpm_find_dbs_satisfier(handle, dblist, depend->name); - - if(provider) { - const char *provname = alpm_pkg_get_name(provider); - - if(alpm_list_find_str(walked, provname)) { - /* if we've already seen this package, don't print in "unique" output - * and don't recurse */ - if(!unique) { - print(alpm_pkg_get_name(pkg), provname, depend->name, depth); + print(alpm_pkg_get_name(pkg), alpm_pkg_get_name(dep_pkg), pkgname, depth); + if(dep_pkg) { + tdepth d = { + depth, + NULL, + depth->level + 1 + }; + depth->next = &d; + /* last dep, cut off the limb here */ + if(!alpm_list_next(i)){ + if(depth->prev){ + depth->prev->next = &d; + d.prev = depth->prev; + depth = &d; + } else { + d.prev = NULL; + } } - } else { - print(alpm_pkg_get_name(pkg), provname, depend->name, depth); - walk_deps(dblist, provider, depth + 1); + walk_deps(dblist, dep_pkg, &d, rev); + depth->next = NULL; } - } else { - /* unresolvable package */ - print(alpm_pkg_get_name(pkg), NULL, depend->name, depth); } } + + if(rev) { + FREELIST(deps); + } } int main(int argc, char *argv[]) { int freelist = 0, ret = 0; - enum _alpm_errno_t err; + alpm_errno_t err; const char *target_name; alpm_pkg_t *pkg; alpm_list_t *dblist = NULL; @@ -467,9 +478,9 @@ int main(int argc, char *argv[]) ret = 1; goto finish; } - dblist = alpm_option_get_syncdbs(handle); + dblist = alpm_get_syncdbs(handle); } else { - dblist = alpm_list_add(dblist, alpm_option_get_localdb(handle)); + dblist = alpm_list_add(dblist, alpm_get_localdb(handle)); freelist = 1; } @@ -485,11 +496,12 @@ int main(int argc, char *argv[]) print_start(alpm_pkg_get_name(pkg), target_name); - if(reverse) { - walk_reverse_deps(dblist, pkg, 1); - } else { - walk_deps(dblist, pkg, 1); - } + tdepth d = { + NULL, + NULL, + 1 + }; + walk_deps(dblist, pkg, &d, reverse); print_end(); diff --git a/src/util/testdb.c b/src/util/testdb.c index d85687a4..2017b60f 100644 --- a/src/util/testdb.c +++ b/src/util/testdb.c @@ -17,8 +17,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" - #include <unistd.h> #include <stdio.h> #include <stdlib.h> @@ -94,17 +92,16 @@ static int check_localdb_files(void) return ret; } -static int checkdeps(alpm_list_t *pkglist) +static int check_deps(alpm_list_t *pkglist) { alpm_list_t *data, *i; int ret = 0; /* check dependencies */ data = alpm_checkdeps(handle, pkglist, NULL, pkglist, 0); for(i = data; i; i = alpm_list_next(i)) { - alpm_depmissing_t *miss = alpm_list_getdata(i); + alpm_depmissing_t *miss = i->data; char *depstring = alpm_dep_compute_string(miss->depend); - printf("missing dependency for %s : %s\n", miss->target, - depstring); + printf("missing %s dependency for %s\n", depstring, miss->target); free(depstring); ret++; } @@ -112,14 +109,14 @@ static int checkdeps(alpm_list_t *pkglist) return ret; } -static int checkconflicts(alpm_list_t *pkglist) +static int check_conflicts(alpm_list_t *pkglist) { alpm_list_t *data, *i; int ret = 0; /* check conflicts */ data = alpm_checkconflicts(handle, pkglist); for(i = data; i; i = i->next) { - alpm_conflict_t *conflict = alpm_list_getdata(i); + alpm_conflict_t *conflict = i->data; printf("%s conflicts with %s\n", conflict->package1, conflict->package2); ret++; @@ -128,6 +125,77 @@ static int checkconflicts(alpm_list_t *pkglist) return ret; } +struct fileitem { + alpm_file_t *file; + alpm_pkg_t *pkg; +}; + +static int fileitem_cmp(const void *p1, const void *p2) +{ + const struct fileitem * fi1 = p1; + const struct fileitem * fi2 = p2; + return strcmp(fi1->file->name, fi2->file->name); +} + +static int check_filelists(alpm_list_t *pkglist) +{ + alpm_list_t *i; + int ret = 0; + size_t list_size = 4096; + size_t offset = 0, j; + struct fileitem *all_files; + struct fileitem *prev_fileitem = NULL; + + all_files = malloc(list_size * sizeof(struct fileitem)); + + for(i = pkglist; i; i = i->next) { + alpm_pkg_t *pkg = i->data; + alpm_filelist_t *filelist = alpm_pkg_get_files(pkg); + for(j = 0; j < filelist->count; j++) { + alpm_file_t *file = filelist->files + j; + /* only add files, not directories, to our big list */ + if(file->name[strlen(file->name) - 1] == '/') { + continue; + } + + /* do we need to reallocate and grow our array? */ + if(offset >= list_size) { + struct fileitem *new_files; + new_files = realloc(all_files, list_size * 2 * sizeof(struct fileitem)); + if(!new_files) { + free(all_files); + return 1; + } + all_files = new_files; + list_size *= 2; + } + + /* we can finally add it to the list */ + all_files[offset].file = file; + all_files[offset].pkg = pkg; + offset++; + } + } + + /* now sort the list so we can find duplicates */ + qsort(all_files, offset, sizeof(struct fileitem), fileitem_cmp); + + /* do a 'uniq' style check on the list */ + for(j = 0; j < offset; j++) { + struct fileitem *fileitem = all_files + j; + if(prev_fileitem && fileitem_cmp(prev_fileitem, fileitem) == 0) { + printf("file owned by %s and %s: %s\n", + alpm_pkg_get_name(prev_fileitem->pkg), + alpm_pkg_get_name(fileitem->pkg), + fileitem->file->name); + } + prev_fileitem = fileitem; + } + + free(all_files); + return ret; +} + static int check_localdb(void) { int ret = 0; @@ -139,10 +207,11 @@ static int check_localdb(void) return ret; } - db = alpm_option_get_localdb(handle); + db = alpm_get_localdb(handle); pkglist = alpm_db_get_pkgcache(db); - ret += checkdeps(pkglist); - ret += checkconflicts(pkglist); + ret += check_deps(pkglist); + ret += check_conflicts(pkglist); + ret += check_filelists(pkglist); return ret; } @@ -154,8 +223,8 @@ static int check_syncdbs(alpm_list_t *dbnames) const alpm_siglevel_t level = ALPM_SIG_DATABASE | ALPM_SIG_DATABASE_OPTIONAL; for(i = dbnames; i; i = alpm_list_next(i)) { - char *dbname = alpm_list_getdata(i); - db = alpm_db_register_sync(handle, dbname, level); + const char *dbname = i->data; + db = alpm_register_syncdb(handle, dbname, level); if(db == NULL) { fprintf(stderr, "error: could not register sync database (%s)\n", alpm_strerror(alpm_errno(handle))); @@ -165,7 +234,7 @@ static int check_syncdbs(alpm_list_t *dbnames) pkglist = alpm_db_get_pkgcache(db); syncpkglist = alpm_list_join(syncpkglist, alpm_list_copy(pkglist)); } - ret += checkdeps(syncpkglist); + ret += check_deps(syncpkglist); cleanup: alpm_list_free(syncpkglist); @@ -184,8 +253,8 @@ static void usage(void) int main(int argc, char *argv[]) { - int ret = 0; - enum _alpm_errno_t err; + int errors = 0; + alpm_errno_t err; const char *dbpath = DBPATH; int a = 1; alpm_list_t *dbnames = NULL; @@ -216,13 +285,13 @@ int main(int argc, char *argv[]) alpm_option_set_logcb(handle, output_cb); if(!dbnames) { - ret = check_localdb(); + errors = check_localdb(); } else { - ret = check_syncdbs(dbnames); + errors = check_syncdbs(dbnames); alpm_list_free(dbnames); } - cleanup(ret); + cleanup(errors > 0); } /* vim: set ts=2 sw=2 noet: */ diff --git a/src/util/testpkg.c b/src/util/testpkg.c index 90758e16..96400a75 100644 --- a/src/util/testpkg.c +++ b/src/util/testpkg.c @@ -41,7 +41,7 @@ int main(int argc, char *argv[]) { int retval = 1; /* default = false */ alpm_handle_t *handle; - enum _alpm_errno_t err; + alpm_errno_t err; alpm_pkg_t *pkg = NULL; const alpm_siglevel_t level = ALPM_SIG_PACKAGE | ALPM_SIG_PACKAGE_OPTIONAL; @@ -59,6 +59,9 @@ int main(int argc, char *argv[]) /* let us get log messages from libalpm */ alpm_option_set_logcb(handle, output_cb); + /* set gpgdir to default */ + alpm_option_set_gpgdir(handle, GPGDIR); + if(alpm_pkg_load(handle, argv[1], 1, level, &pkg) == -1 || pkg == NULL) { err = alpm_errno(handle); diff --git a/test/pacman/README b/test/pacman/README index a3c36fc9..ae3303a3 100644 --- a/test/pacman/README +++ b/test/pacman/README @@ -108,7 +108,6 @@ is not necessarily complete: - HoldPkg - IgnorePkg - IgnoreGroup - - SyncFirst - NoExtract - NoUpgrade - XferCommand diff --git a/test/pacman/pactest.py b/test/pacman/pactest.py index bb198eb4..2fb64edc 100755 --- a/test/pacman/pactest.py +++ b/test/pacman/pactest.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/python2 # # pactest : run automated testing on the pacman binary # diff --git a/test/pacman/pmdb.py b/test/pacman/pmdb.py index b94c6cf6..285c3151 100644 --- a/test/pacman/pmdb.py +++ b/test/pacman/pmdb.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/python2 # # Copyright (c) 2006 by Aurelien Foret <orelien@chez.com> # diff --git a/test/pacman/pmenv.py b/test/pacman/pmenv.py index 04aecd9a..0e455cee 100644 --- a/test/pacman/pmenv.py +++ b/test/pacman/pmenv.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/python2 # # Copyright (c) 2006 by Aurelien Foret <orelien@chez.com> # diff --git a/test/pacman/pmfile.py b/test/pacman/pmfile.py index cdcc7715..d5aa1a11 100644 --- a/test/pacman/pmfile.py +++ b/test/pacman/pmfile.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/python2 # # Copyright (c) 2006 by Aurelien Foret <orelien@chez.com> # diff --git a/test/pacman/pmpkg.py b/test/pacman/pmpkg.py index 00f345c0..bfc93dd6 100644 --- a/test/pacman/pmpkg.py +++ b/test/pacman/pmpkg.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/python2 # # Copyright (c) 2006 by Aurelien Foret <orelien@chez.com> # diff --git a/test/pacman/pmrule.py b/test/pacman/pmrule.py index 70c8838e..778b6aac 100644 --- a/test/pacman/pmrule.py +++ b/test/pacman/pmrule.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/python2 # # Copyright (c) 2006 by Aurelien Foret <orelien@chez.com> # @@ -87,8 +87,11 @@ class pmrule(object): if not value in newpkg.depends: success = 0 elif case == "OPTDEPENDS": - if not value in newpkg.optdepends: - success = 0 + success = 0 + for optdep in newpkg.optdepends: + if value == optdep.split(':', 1)[0]: + success = 1 + break elif case == "REASON": if newpkg.reason != int(value): success = 0 diff --git a/test/pacman/pmtest.py b/test/pacman/pmtest.py index 4e1ecd0b..1a026864 100644 --- a/test/pacman/pmtest.py +++ b/test/pacman/pmtest.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/python2 # # Copyright (c) 2006 by Aurelien Foret <orelien@chez.com> # diff --git a/test/pacman/tests/Makefile.am b/test/pacman/tests/Makefile.am index 508534ac..9ab0c777 100644 --- a/test/pacman/tests/Makefile.am +++ b/test/pacman/tests/Makefile.am @@ -17,11 +17,9 @@ edit = sed \ $(CONFTESTS): Makefile - @echo ' ' GEN $@; - @$(RM) $@ $@.tmp - @test -f $(srcdir)/$@.in && $(edit) $(srcdir)/$@.in >$@.tmp || true - @test -f $@.tmp || false - @chmod a-w $@.tmp - @mv $@.tmp $@ + $(AM_V_at)$(RM) $@ $@.tmp + $(AM_V_GEN)test -f $(srcdir)/$@.in && $(edit) $(srcdir)/$@.in >$@.tmp || true + $(AM_V_at)chmod a-w $@.tmp + $(AM_V_at)mv $@.tmp $@ # vim:set ts=2 sw=2 noet: diff --git a/test/pacman/tests/fileconflict011.py b/test/pacman/tests/fileconflict011.py new file mode 100644 index 00000000..af48a067 --- /dev/null +++ b/test/pacman/tests/fileconflict011.py @@ -0,0 +1,17 @@ +self.description = "dir->file change during package upgrade (filesystem directory conflict)" + +lp1 = pmpkg("pkg1") +lp1.files = ["dir/"] +self.addpkg2db("local", lp1) + +self.filesystem = ["dir/conflict/"] + +p = pmpkg("pkg1", "1.0-2") +p.files = ["dir"] +self.addpkg2db("sync", p) + +self.args = "-S pkg1" + +self.addrule("PACMAN_RETCODE=1") +self.addrule("PKG_VERSION=pkg1|1.0-1") +self.addrule("DIR_EXIST=dir/conflict/") diff --git a/test/pacman/tests/fileconflict012.py b/test/pacman/tests/fileconflict012.py index 421b739a..95ab5681 100644 --- a/test/pacman/tests/fileconflict012.py +++ b/test/pacman/tests/fileconflict012.py @@ -14,4 +14,4 @@ self.args = "-S pkg1" self.addrule("PACMAN_RETCODE=1") self.addrule("PKG_VERSION=pkg1|1.0-1") -self.addrule("DIR_EXIST=dir/") +self.addrule("FILE_EXIST=dir/file") diff --git a/test/pacman/tests/fileconflict013.py b/test/pacman/tests/fileconflict013.py new file mode 100644 index 00000000..521b62e8 --- /dev/null +++ b/test/pacman/tests/fileconflict013.py @@ -0,0 +1,22 @@ +self.description = "file->file path change with same effective path (/lib as symlink)" + +lp1 = pmpkg("filesystem", "1.0-1") +lp1.files = ["usr/", + "usr/lib/", + "lib -> usr/lib/"] +self.addpkg2db("local", lp1) + +lp2 = pmpkg("pkg1", "1.0-1") +lp2.files = ["lib/libfoo.so"] +self.addpkg2db("local", lp2) + +sp1 = pmpkg("pkg1", "1.0-2") +sp1.files = ["usr/lib/libfoo.so"] +self.addpkg2db("sync", sp1) + +self.args = "-Su" + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_VERSION=pkg1|1.0-2") + +self.expectfailure = True diff --git a/test/pacman/tests/fileconflict015.py b/test/pacman/tests/fileconflict015.py new file mode 100644 index 00000000..78634d7e --- /dev/null +++ b/test/pacman/tests/fileconflict015.py @@ -0,0 +1,17 @@ +self.description = "conflict between a directory and a file" + +p1 = pmpkg("pkg1") +p1.files = ["foo/"] +self.addpkg2db("sync", p1) + +p2 = pmpkg("pkg2") +p2.files = ["foo"] +self.addpkg2db("sync", p2) + +self.args = "-S pkg1 pkg2" + +self.addrule("PACMAN_RETCODE=1") +self.addrule("!PKG_EXIST=pkg1") +self.addrule("!PKG_EXIST=pkg2") + +self.expectfailure = True diff --git a/test/pacman/tests/fileconflict016.py b/test/pacman/tests/fileconflict016.py new file mode 100644 index 00000000..93797f64 --- /dev/null +++ b/test/pacman/tests/fileconflict016.py @@ -0,0 +1,23 @@ +self.description = "file conflict with same effective path across packages (directory symlink)" + +lp1 = pmpkg("filesystem", "1.0-1") +lp1.files = ["usr/", + "usr/lib/", + "lib -> usr/lib/"] +self.addpkg2db("local", lp1) + +p1 = pmpkg("pkg1") +p1.files = ["lib/foo"] +self.addpkg2db("sync", p1) + +p2 = pmpkg("pkg2") +p2.files = ["usr/lib/foo"] +self.addpkg2db("sync", p2) + +self.args = "-S pkg1 pkg2" + +self.addrule("PACMAN_RETCODE=1") +self.addrule("!PKG_EXIST=pkg1") +self.addrule("!PKG_EXIST=pkg2") + +self.expectfailure = True diff --git a/test/pacman/tests/ignore008.py b/test/pacman/tests/ignore008.py new file mode 100644 index 00000000..12416ad9 --- /dev/null +++ b/test/pacman/tests/ignore008.py @@ -0,0 +1,29 @@ +self.description = "Sync with relevant ignored fnmatched packages" + +package1 = pmpkg("foopkg", "1.0-1") +self.addpkg2db("local", package1) + +package2 = pmpkg("barpkg", "2.0-1") +self.addpkg2db("local", package2) + +package3 = pmpkg("bazpkg", "3.0-1") +self.addpkg2db("local", package3) + + +package1up = pmpkg("foopkg", "2.0-1") +self.addpkg2db("sync", package1up) + +package2up = pmpkg("barpkg", "3.0-1") +self.addpkg2db("sync", package2up) + +package3up = pmpkg("bazpkg", "4.0-1") +self.addpkg2db("sync", package3up) + +self.option["IgnorePkg"] = ["foo*", "ba?pkg"] +self.args = "-Su" + + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_VERSION=foopkg|1.0-1") +self.addrule("PKG_VERSION=barpkg|2.0-1") +self.addrule("PKG_VERSION=bazpkg|3.0-1") diff --git a/test/pacman/tests/query007.py b/test/pacman/tests/query007.py new file mode 100644 index 00000000..35bb0ca6 --- /dev/null +++ b/test/pacman/tests/query007.py @@ -0,0 +1,11 @@ +self.description = "Query ownership of file in root" + +sp = pmpkg("dummy") +sp.files = ["etc/config"] +self.addpkg2db("local", sp) + +self.filesystem = ["config"] + +self.args = "-Qo /config" + +self.addrule("PACMAN_RETCODE=1") diff --git a/test/pacman/tests/remove031.py b/test/pacman/tests/remove031.py new file mode 100644 index 00000000..0ea09c87 --- /dev/null +++ b/test/pacman/tests/remove031.py @@ -0,0 +1,11 @@ +self.description = "Remove a package in HoldPkg" + +p1 = pmpkg("foopkg") +self.addpkg2db("local", p1) + +self.option["HoldPkg"] = ["???pkg"] + +self.args = "-R %s" % p1.name + +self.addrule("PACMAN_RETCODE=1") +self.addrule("PKG_EXIST=foopkg") diff --git a/test/pacman/tests/sync139.py b/test/pacman/tests/sync139.py new file mode 100644 index 00000000..0b0526d8 --- /dev/null +++ b/test/pacman/tests/sync139.py @@ -0,0 +1,23 @@ +self.description = "Sysupgrade of packages in fnmatch'd IgnoreGroup" + +sp1 = pmpkg("pkg1", "1.0-2") +sp1.groups = ["grp"] +sp2 = pmpkg("pkg2", "1.0-2") +sp2.groups = ["grp2"] + +for p in sp1, sp2: + self.addpkg2db("sync", p) + +lp1 = pmpkg("pkg1", "1.0-1") +lp2 = pmpkg("pkg2", "1.0-1") + +for p in lp1, lp2: + self.addpkg2db("local", p) + +self.option["IgnoreGroup"] = ["grp"] + +self.args = "-Su" + +self.addrule("PACMAN_RETCODE=0") +self.addrule("PKG_VERSION=pkg1|1.0-1") +self.addrule("PKG_VERSION=pkg2|1.0-2") diff --git a/test/pacman/tests/sync301.py b/test/pacman/tests/sync301.py deleted file mode 100644 index 96402fc3..00000000 --- a/test/pacman/tests/sync301.py +++ /dev/null @@ -1,27 +0,0 @@ -self.description = "Sysupgrade : pacman needs to be upgraded and has new deps" - -sp = pmpkg("pacman", "1.0-2") -sp.depends = ["dep"] -self.addpkg2db("sync", sp) - -spdep = pmpkg("dep") -self.addpkg2db("sync", spdep) - -sp1 = pmpkg("pkg1", "1.0-2") -self.addpkg2db("sync", sp1) - -lp = pmpkg("pacman", "1.0-1") -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") diff --git a/test/pacman/tests/sync302.py b/test/pacman/tests/sync302.py deleted file mode 100644 index 78e45c33..00000000 --- a/test/pacman/tests/sync302.py +++ /dev/null @@ -1,49 +0,0 @@ -self.description = "Sysupgrade : pacman needs to be upgraded and has updated deps" - -sp = pmpkg("pacman", "1.0-2") -sp.depends = ["zlib", "curl", "libarchive"] -self.addpkg2db("sync", sp) - -libcdep = pmpkg("glibc", "2.15-1") -self.addpkg2db("sync", libcdep) - -curldep = pmpkg("curl", "7.22-1") -self.addpkg2db("sync", curldep) - -libadep = pmpkg("libarchive", "2.8.5-1") -self.addpkg2db("sync", libadep) - -zlibdep = pmpkg("zlib", "1.2.5-3") -zlibdep.depends = ["glibc"] -self.addpkg2db("sync", zlibdep) - - -lp = pmpkg("pacman", "1.0-1") -self.addpkg2db("local", lp) - -lp1 = pmpkg("curl", "7.21.7-1") -self.addpkg2db("local", lp1) - -lp2 = pmpkg("glibc", "2.13-1") -self.addpkg2db("local", lp2) - -lp3 = pmpkg("libarchive", "2.8.4-1") -self.addpkg2db("local", lp3) - -lp4 = pmpkg("zlib", "1.2.5-3") -self.addpkg2db("local", lp4) - -self.option["SyncFirst"] = ["pacman"] - -self.args = "-Su" - -self.addrule("PACMAN_RETCODE=0") -self.addrule("PKG_VERSION=pacman|1.0-2") -self.addrule("PKG_EXIST=glibc") -self.addrule("PKG_EXIST=curl") -self.addrule("PKG_EXIST=libarchive") -# TODO: when SyncFirst recursive comes back, re-enable these -#self.addrule("PKG_VERSION=glibc|2.15-1") -#self.addrule("PKG_VERSION=curl|7.22-1") -#self.addrule("PKG_VERSION=libarchive|2.8.5-1") -self.addrule("PKG_EXIST=zlib") diff --git a/test/pacman/tests/sync303.py b/test/pacman/tests/sync303.py deleted file mode 100644 index 9d7bab58..00000000 --- a/test/pacman/tests/sync303.py +++ /dev/null @@ -1,35 +0,0 @@ -self.description = "Sysupgrade: upgrade pacman with deps as provisions" - -sp = pmpkg("pacman", "1.0-2") -sp.depends = ["zlib"] -self.addpkg2db("sync", sp) - -glibcdep = pmpkg("glibc", "2.13-1") -self.addpkg2db("sync", glibcdep) - -zlibdep = pmpkg("zlib", "1.2.5-3") -zlibdep.depends = ["glibc"] -self.addpkg2db("sync", zlibdep) - - -lp = pmpkg("pacman", "1.0-1") -lp.depends = ["zlib"] -self.addpkg2db("local", lp) - -lp2 = pmpkg("glibc-awesome", "2.13-2") -lp2.provides = ["glibc=2.13"] -lp2.conflicts = ["glibc"] -self.addpkg2db("local", lp2) - -lp3 = pmpkg("zlib", "1.2.5-3") -self.addpkg2db("local", lp3) - -self.option["SyncFirst"] = ["pacman"] - -self.args = "-Su" - -self.addrule("PACMAN_RETCODE=0") -self.addrule("PKG_VERSION=pacman|1.0-2") -self.addrule("PKG_EXIST=glibc-awesome") -self.addrule("PKG_VERSION=glibc-awesome|2.13-2") -self.addrule("PKG_EXIST=zlib") diff --git a/test/pacman/tests/sync304.py b/test/pacman/tests/sync304.py deleted file mode 100644 index 18058c99..00000000 --- a/test/pacman/tests/sync304.py +++ /dev/null @@ -1,25 +0,0 @@ -self.description = "Sysupgrade: upgrade pacman being depended on" - -sp = pmpkg("pacman", "4.0.1-1") -self.addpkg2db("sync", sp) - -sp2 = pmpkg("pyalpm", "2-1") -sp2.depends = ["pacman>=4.0", "pacman<4.1"] -self.addpkg2db("sync", sp2) - -lp = pmpkg("pacman", "3.5.4-1") -self.addpkg2db("local", lp) - -lp2 = pmpkg("pyalpm", "1-1") -lp2.depends = ["pacman>=3.5", "pacman<3.6"] -self.addpkg2db("local", lp2) - -self.option["SyncFirst"] = ["pacman"] - -self.args = "-Su" - -self.addrule("PACMAN_RETCODE=0") -self.addrule("PKG_VERSION=pacman|4.0.1-1") -self.addrule("PKG_VERSION=pyalpm|2-1") - -self.expectfailure = True diff --git a/test/pacman/tests/sync305.py b/test/pacman/tests/sync305.py deleted file mode 100644 index 62005b58..00000000 --- a/test/pacman/tests/sync305.py +++ /dev/null @@ -1,64 +0,0 @@ -self.description = "Sysupgrade: syncfirst with recursive/cascading deps" - -sp = pmpkg("pacman", "4.0.1-2") -sp.depends = ["glibc>=2.15", "curl"] -self.addpkg2db("sync", sp) - -glibcdep = pmpkg("glibc", "2.15-1") -self.addpkg2db("sync", glibcdep) - -gcldep = pmpkg("gcc-libs", "4.6.2-5") -gcldep.depends = ["glibc>=2.14"] -self.addpkg2db("sync", gcldep) - -curldep = pmpkg("curl", "7.23.1-2") -curldep.depends = ["openssl"] -self.addpkg2db("sync", curldep) - -openssldep = pmpkg("openssl", "1.0.0.e-1") -openssldep.depends = ["perl"] -self.addpkg2db("sync", openssldep) - -gccdep = pmpkg("gcc", "4.6.2-5") -gccdep.depends = ["gcc-libs=4.6.2-5"] -self.addpkg2db("sync", gccdep) - -perldep = pmpkg("perl", "5.14.2-5") -perldep.depends = ["db"] -self.addpkg2db("sync", perldep) - -dbdep = pmpkg("db", "5.2.36-2") -dbdep.depends = ["gcc-libs"] -self.addpkg2db("sync", dbdep) - - -lp = pmpkg("pacman", "4.0.1-1") -lp.depends = ["glibc>=2.14", "curl"] -self.addpkg2db("local", lp) - -lp2 = pmpkg("glibc", "2.14-2") -self.addpkg2db("local", lp2) - -lp3 = pmpkg("curl", "7.23.1-2") -self.addpkg2db("local", lp3) - -lp4 = pmpkg("gcc-libs", "4.6.2-3") -self.addpkg2db("local", lp4) - -lp5 = pmpkg("gcc", "4.6.2-3") -lp5.depends = ["gcc-libs=4.6.2-3"] -self.addpkg2db("local", lp5) - -lp6 = pmpkg("perl", "5.14.2-5") -lp6.depends = ["db"] -self.addpkg2db("local", lp6) - -lp7 = pmpkg("db", "5.2.36-2") -lp7.depends = ["gcc-libs"] -self.addpkg2db("local", lp7) - -self.option["SyncFirst"] = ["pacman"] - -self.args = "-Su" -self.addrule("PACMAN_RETCODE=0") -self.addrule("PKG_VERSION=pacman|4.0.1-2") diff --git a/test/pacman/tests/sync502.py b/test/pacman/tests/sync502.py new file mode 100644 index 00000000..5cc42c9f --- /dev/null +++ b/test/pacman/tests/sync502.py @@ -0,0 +1,17 @@ +self.description = "Install a package from a sync db with fnmatch'ed NoExtract" + +sp = pmpkg("dummy") +sp.files = ["bin/dummy", + "usr/share/man/man8", + "usr/share/man/man1/dummy.1"] +self.addpkg2db("sync", sp) + +self.option["NoExtract"] = ["usr/share/man/*"] + +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/share/man/man8") +self.addrule("!FILE_EXIST=usr/share/man/man1/dummy.1") diff --git a/test/pacman/tests/sync503.py b/test/pacman/tests/sync503.py new file mode 100644 index 00000000..9d24f00d --- /dev/null +++ b/test/pacman/tests/sync503.py @@ -0,0 +1,18 @@ +self.description = "Upgrade a package, with a fnmatch 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.*"] + +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/test/pacman/tests/sync700.py b/test/pacman/tests/sync700.py new file mode 100644 index 00000000..0002b643 --- /dev/null +++ b/test/pacman/tests/sync700.py @@ -0,0 +1,22 @@ +self.description = "do not remove directory symlink if another package has file in its path" + +lp1 = pmpkg("pkg1") +lp1.files = ["usr/lib/foo", + "lib -> usr/lib"] +self.addpkg2db("local", lp1) + +lp2 = pmpkg("pkg2") +lp2.files = ["lib/bar"] +self.addpkg2db("local", lp2) + +p = pmpkg("pkg1", "1.0-2") +p.files = ["usr/lib/foo"] +self.addpkg2db("sync", p) + +self.args = "-S pkg1" + +self.addrule("PACMAN_RETCODE=1") +self.addrule("PKG_VERSION=pkg1|1.0-1") +self.addrule("FILE_EXIST=/lib/bar") + +self.expectfailure = True diff --git a/test/pacman/tests/sync701.py b/test/pacman/tests/sync701.py new file mode 100644 index 00000000..201f6028 --- /dev/null +++ b/test/pacman/tests/sync701.py @@ -0,0 +1,22 @@ +self.description = "do not remove directory symlink if incoming package has file in its path (order 1)" + +lp = pmpkg("pkg1") +lp.files = ["usr/lib/foo", + "lib -> usr/lib"] +self.addpkg2db("local", lp) + +p1 = pmpkg("pkg1", "1.0-2") +p1.files = ["usr/lib/foo"] +self.addpkg2db("sync", p1) + +p2 = pmpkg("pkg2") +p2.files = ["lib/bar"] +self.addpkg2db("sync", p2) + +self.args = "-S pkg1 pkg2" + +self.addrule("PACMAN_RETCODE=1") +self.addrule("PKG_VERSION=pkg1|1.0-1") +self.addrule("!PKG_EXIST=pkg2") + +self.expectfailure = True diff --git a/test/pacman/tests/sync702.py b/test/pacman/tests/sync702.py new file mode 100644 index 00000000..ee4eef95 --- /dev/null +++ b/test/pacman/tests/sync702.py @@ -0,0 +1,22 @@ +self.description = "do not remove directory symlink if incoming package has file in its path (order 2)" + +lp = pmpkg("pkg2") +lp.files = ["usr/lib/foo", + "lib -> usr/lib"] +self.addpkg2db("local", lp) + +p1 = pmpkg("pkg1") +p1.files = ["lib/bar"] +self.addpkg2db("sync", p1) + +p2 = pmpkg("pkg2", "1.0-2") +p2.files = ["usr/lib/foo"] +self.addpkg2db("sync", p2) + +self.args = "-S pkg1 pkg2" + +self.addrule("PACMAN_RETCODE=1") +self.addrule("PKG_VERSION=pkg2|1.0-1") +self.addrule("!PKG_EXIST=pkg1") + +self.expectfailure = True diff --git a/test/pacman/tests/upgrade012.py b/test/pacman/tests/upgrade012.py index dba8dc18..4d9f0cd1 100644 --- a/test/pacman/tests/upgrade012.py +++ b/test/pacman/tests/upgrade012.py @@ -6,7 +6,7 @@ self.addpkg(p) self.filesystem = ["bin/dummy"] -self.args = "-Uf %s" % p.filename() +self.args = "-U --force %s" % p.filename() self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_EXIST=dummy") diff --git a/test/pacman/tests/upgrade014.py b/test/pacman/tests/upgrade014.py index 1632dd36..93c2fe2b 100644 --- a/test/pacman/tests/upgrade014.py +++ b/test/pacman/tests/upgrade014.py @@ -13,7 +13,7 @@ p2.files = ["bin/foobar", for p in p1, p2: self.addpkg(p) -self.args = "-Uf %s" % " ".join([p.filename() for p in p1, p2]) +self.args = "-U --force %s" % " ".join([p.filename() for p in p1, p2]) self.addrule("PACMAN_RETCODE=0") for p in p1, p2: diff --git a/test/pacman/tests/upgrade015.py b/test/pacman/tests/upgrade015.py index 22f7c36b..ea6046cb 100644 --- a/test/pacman/tests/upgrade015.py +++ b/test/pacman/tests/upgrade015.py @@ -6,7 +6,7 @@ self.addpkg(p) self.filesystem = ["etc/dummy.conf"] -self.args = "-Uf %s" % p.filename() +self.args = "-U --force %s" % p.filename() self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_EXIST=dummy") diff --git a/test/pacman/tests/upgrade016.py b/test/pacman/tests/upgrade016.py index dd31c9ab..b6b3f3ae 100644 --- a/test/pacman/tests/upgrade016.py +++ b/test/pacman/tests/upgrade016.py @@ -7,7 +7,7 @@ self.addpkg(p) self.filesystem = ["etc/dummy.conf"] -self.args = "-Uf %s" % p.filename() +self.args = "-U --force %s" % p.filename() self.addrule("PACMAN_RETCODE=0") self.addrule("PKG_EXIST=dummy") diff --git a/test/pacman/tests/upgrade046.py b/test/pacman/tests/upgrade046.py index 12390647..a02a7132 100644 --- a/test/pacman/tests/upgrade046.py +++ b/test/pacman/tests/upgrade046.py @@ -20,7 +20,7 @@ p2.files = ["bin/foobar"] for p in p1, p2: self.addpkg(p) -self.args = "-Uf %s" % " ".join([p.filename() for p in p1, p2]) +self.args = "-U --force %s" % " ".join([p.filename() for p in p1, p2]) self.addrule("PACMAN_RETCODE=0") for p in p1, p2: diff --git a/test/pacman/util.py b/test/pacman/util.py index 81dcc906..d40612dc 100644 --- a/test/pacman/util.py +++ b/test/pacman/util.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/python2 # # Copyright (c) 2006 by Aurelien Foret <orelien@chez.com> # diff --git a/test/scripts/Makefile.am b/test/scripts/Makefile.am new file mode 100644 index 00000000..d525d894 --- /dev/null +++ b/test/scripts/Makefile.am @@ -0,0 +1,10 @@ +check_SCRIPTS = \ + parseopts_test.sh \ + human_to_size_test.sh + +noinst_SCRIPTS = $(check_SCRIPTS) + +EXTRA_DIST = \ + $(check_SCRIPTS) + +# vim:set ts=2 sw=2 noet: diff --git a/test/scripts/human_to_size_test.sh b/test/scripts/human_to_size_test.sh new file mode 100644 index 00000000..dbf1997a --- /dev/null +++ b/test/scripts/human_to_size_test.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +# source the library function +if [[ -z $1 || ! -f $1 ]]; then + printf "error: path to human_to_size library not provided or does not exist\n" + exit 1 +fi +. "$1" + +if ! type -t human_to_size >/dev/null; then + printf 'human_to_size function not found\n' + exit 1 +fi + +parse_hts() { + local input=$1 expected=$2 result + + (( ++testcount )) + + result=$(human_to_size "$1") + if [[ $result = "$expected" ]]; then + (( ++pass )) + else + (( ++fail )) + printf '[TEST %3s]: FAIL\n' "$testcount" + printf ' input: %s\n' "$input" + printf ' output: %s\n' "$result" + printf ' expected: %s\n' "$expected" + fi +} + +summarize() { + if (( !fail )); then + printf 'All %s tests successful\n\n' "$testcount" + exit 0 + else + printf '%s of %s tests failed\n\n' "$fail" "$testcount" + exit 1 + fi +} +trap 'summarize' EXIT + +printf 'Beginning human_to_size tests\n' + +# parse_hts <input> <expected output> + +parse_hts '1MiB' 1048576 + +parse_hts '10XiB' '' + +parse_hts '10 MiB' 10485760 + +parse_hts '10 XiB' '' + +parse_hts '.1 TiB' 109951162778 + +parse_hts ' -3 KiB ' -3072 + +parse_hts 'foo3KiB' '' + +parse_hts '3KiBfoo' '' + +parse_hts '3kib' '' + +parse_hts '+1KiB' 1024 + +parse_hts '+1.0 KiB' 1024 + +parse_hts '1MB' 1000000 + +parse_hts '1M' 1048576 + +parse_hts ' 1 G ' 1073741824 + +parse_hts '1Q' '' diff --git a/test/scripts/parseopts_test.sh b/test/scripts/parseopts_test.sh new file mode 100755 index 00000000..1693b9f9 --- /dev/null +++ b/test/scripts/parseopts_test.sh @@ -0,0 +1,138 @@ +#!/bin/bash + +declare -i testcount=0 pass=0 fail=0 + +# source the library function +if [[ -z $1 || ! -f $1 ]]; then + printf "error: path to parseopts library not provided or does not exist\n" + exit 1 +fi +. "$1" + +if ! type -t parseopts >/dev/null; then + printf 'parseopts function not found\n' + exit 1 +fi + +# borrow opts from makepkg +OPT_SHORT="AcdefFghiLmop:rRsV" +OPT_LONG=('allsource' 'asroot' 'ignorearch' 'check' 'clean:' 'cleanall' 'nodeps' + 'noextract' 'force' 'forcever:' 'geninteg' 'help' 'holdver' + 'install' 'key:' 'log' 'nocolor' 'nobuild' 'nocheck' 'nosign' 'pkg:' 'rmdeps' + 'repackage' 'skipinteg' 'sign' 'source' 'syncdeps' 'version' 'config:' + 'noconfirm' 'noprogressbar') + +parse() { + local result=$1 tokencount=$2; shift 2 + + (( ++testcount )) + parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@" 2>/dev/null + test_result "$result" "$tokencount" "$*" "${OPTRET[@]}" + unset OPTRET +} + +test_result() { + local result=$1 tokencount=$2 input=$3; shift 3 + + if [[ $result = "$*" ]] && (( tokencount == $# )); then + (( ++pass )) + else + printf '[TEST %3s]: FAIL\n' "$testcount" + printf ' input: %s\n' "$input" + printf ' output: %s (%s tokens)\n' "$*" "$#" + printf ' expected: %s (%s tokens)\n' "$result" "$tokencount" + echo + (( ++fail )) + fi +} + +summarize() { + if (( !fail )); then + printf 'All %s tests successful\n\n' "$testcount" + exit 0 + else + printf '%s of %s tests failed\n\n' "$fail" "$testcount" + exit 1 + fi +} +trap 'summarize' EXIT + +printf 'Beginning parseopts tests\n' + +# usage: parse <expected result> <token count> test-params... +# a failed parse will match only the end of options marker '--' + +# no options +parse '--' 1 + +# short options +parse '-s -r --' 3 -s -r + +# short options, no spaces +parse '-s -r --' 3 -sr + +# short opt missing an opt arg +parse '--' 1 -s -p + +# short opt with an opt arg +parse '-p PKGBUILD -L --' 4 -p PKGBUILD -L + +# short opt with an opt arg, no space +parse '-p PKGBUILD --' 3 -pPKGBUILD + +# valid shortopts as a long opt +parse '--' 1 --sir + +# long opt wiht no optarg +parse '--log --' 2 --log + +# long opt with missing optarg +parse '--' 1 -sr --pkg + +# long opt with optarg +parse '--pkg foo --' 3 --pkg foo + +# long opt with optarg with whitespace +parse '--pkg foo bar -- baz' 4 --pkg "foo bar" baz + +# long opt with optarg with = +parse '--pkg foo=bar -- baz' 4 --pkg foo=bar baz + +# long opt with explicit optarg +parse '--pkg bar -- foo baz' 5 foo --pkg=bar baz + +# long opt with explicit optarg, with whitespace +parse '--pkg foo bar -- baz' 4 baz --pkg="foo bar" + +# long opt with explicit optarg that doesn't take optarg +parse '--' 1 --force=always -s + +# long opt with explicit optarg with = +parse '--pkg foo=bar --' 3 --pkg=foo=bar + +# explicit end of options with options after +parse '-s -r -- foo bar baz' 6 -s -r -- foo bar baz + +# non-option parameters mixed in with options +parse '-s -r -- foo baz' 5 -s foo baz -r + +# optarg with whitespace +parse '-p foo bar -s --' 4 -p'foo bar' -s + +# non-option parameter with whitespace +parse '-i -- foo bar' 3 -i 'foo bar' + +# successful stem match (opt has no arg) +parse '--nocolor --' 2 --nocol + +# successful stem match (opt has arg) +parse '--config foo --' 3 --conf foo + +# ambiguous long opt +parse '--' 1 '--for' + +# exact match on a possible stem (--force & --forcever) +parse '--force --' 2 --force + +# exact match on possible stem (opt has optarg) +parse '--clean foo --' 3 --clean=foo |