summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJudd Vinet <judd@archlinux.org>2003-09-03 04:09:29 +0200
committerJudd Vinet <judd@archlinux.org>2003-09-03 04:09:29 +0200
commitf8bfe729e49fe5d7fd7df80733ad3d2d1c61160d (patch)
treeb74d15bfa71703e08f0a815bcc4353b2449db6a4
parentffe1d50cff3e1df8834f371e1b7a40fa2c703e9b (diff)
downloadpacman-f8bfe729e49fe5d7fd7df80733ad3d2d1c61160d.tar.gz
pacman-f8bfe729e49fe5d7fd7df80733ad3d2d1c61160d.tar.xz
Imported from pacman-2.6.tar.gz
-rw-r--r--ChangeLog27
-rw-r--r--Makefile.in2
-rw-r--r--TODO14
-rwxr-xr-xcnvpkg19
-rw-r--r--doc/makepkg.8.in84
-rw-r--r--doc/pacman.8.in20
-rw-r--r--etc/makepkg.conf14
-rw-r--r--etc/pacman.conf38
-rwxr-xr-xscripts/gensync75
-rwxr-xr-xscripts/makepkg278
-rwxr-xr-xscripts/makeworld189
-rw-r--r--src/convertdb.c2
-rw-r--r--src/db.c112
-rw-r--r--src/db.h5
-rw-r--r--src/list.c6
-rw-r--r--src/list.h2
-rw-r--r--src/package.c57
-rw-r--r--src/package.h5
-rw-r--r--src/pacman.c1029
-rw-r--r--src/pacman.h9
-rw-r--r--src/pacsync.c129
-rw-r--r--src/pacsync.h7
-rw-r--r--src/rpmvercmp.c2
-rw-r--r--src/rpmvercmp.h2
-rw-r--r--src/util.c15
-rw-r--r--src/util.h2
-rw-r--r--src/vercmp.c2
27 files changed, 1600 insertions, 546 deletions
diff --git a/ChangeLog b/ChangeLog
index 7765bfda..a147606b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,27 @@
VERSION DESCRIPTION
-------------------------------------------------------------------
-2.5.1 - Added retries to the downloader to get around some
- transient network errors. (this will likely be an option
- in pacman.conf for later versions)
+-----------------------------------------------------------------------------
+2.6 - Added group handling, so one can run 'pacman -S kde' and
+ install all files from the KDE group
+ - Fixed a duplication bug in cascade package removal
+ - Added support for virtual provisions with "provides" tags
+ - When conflicts are encountered, pacman now offers the chance
+ to remove the conflicting packages (provides or literals)
+ - Added support for renamed/combined packages with a "replaces"
+ tag
+ - Added --nostrip option to makepkg
+ - Improved --search to list all packages from all repos when
+ a search term is omitted
+ - Added logging support through syslog()
+ - Added fakeroot support to makepkg (RomanK)
+ - Added MD5sum generation/validation to makepkg (RomanK)
+ - Fixed a progress bar bug (Aurelien Foret)
+ - Sorted makepkg's .FILELISTs (Aurelien Foret)
+ - Targets are now re-ordered w.r.t. dependencies when
+ using -A/-U
+ - Modified --search to work when called as -Sys
+ - Modified abs to use ABS_ROOT from /etc/abs/abs.conf (Aurelien)
+ - Other bug fixes
+2.5.1 - Minor bug fixes
2.5 - Added an URL tag to package info
- Sped up package load times by about 500% by introducing
a .FILELIST into the package
diff --git a/Makefile.in b/Makefile.in
index c4d66c31..fb0ab827 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -34,7 +34,7 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
-PACVER = 2.5.1
+PACVER = 2.6
TOPDIR = @srcdir@
SRCDIR = $(TOPDIR)/src/
diff --git a/TODO b/TODO
index add6b4be..90e03b36 100644
--- a/TODO
+++ b/TODO
@@ -1,29 +1,15 @@
- fix the broken pipe bug
-- add some logging mechanism (/var/log/pacman.log)
- handle version comparators in makepkg dep resolution (eg, glibc>=2.2.5)
-- have "group" designations
- record md5sums of all files in a package
-- add a way to clean /var/cache/pacman/src
-- duplicate dep checks occur with sync (one in sync, one in add)
-- if a package is removed with --nodeps and re-installed, the requiredby
- fields of it's required packages are not updated
-- add an option equivalent to 'pacman -Ql pkg | grep filename'
-- add other options to config file: db location, overwrite behaviour, etc.
-- use the COLUMNS env var for the progress bar
? use 'set -e' in makepkg?
x if a package fails, ask before aborting the full operation
- can't -- further dependent packages may fail b/c of the first failure
-? ask, then remove conflicting packages with --sync
-? use a provides tag (instead of an OR operator in depends)
-- add a 'cascade' option to --remove that will remove a package and
- all requiredby packages under it
- check $PACCONF env var
? use a 'trust pacman' config option for downgrading?
? build-time (source) dependencies in makepkg
? run ldd on every executable in a newly built package to find required so's
- add a --pretend option
- add a consistency/sanity check operation (md5 tracking for all files)
-- add a --dbpath option
- use package caches more for performance
- clean up output a bit (message queue?)
- use a files.cache db for --owns and db_find_conflicts
diff --git a/cnvpkg b/cnvpkg
deleted file mode 100755
index 2a164c12..00000000
--- a/cnvpkg
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-
-TMPDIR=/tmp/.pkgcnv
-TMPFILE=/tmp/.pkgcnvf
-tl=`pwd`
-
-for fn in $*; do
- rm -rf $TMPDIR;
- mkdir -p $TMPDIR;
- echo "Converting $fn"
- cd $TMPDIR
- tar zxvf $tl/$fn | grep -v '^.PKGINFO' | grep -v '._install' >$TMPFILE
- mv $TMPFILE ./.FILELIST
- if [ -f ._install ]; then
- tar cfz /new/$fn .PKGINFO .FILELIST ._install *
- else
- tar cfz /new/$fn .PKGINFO .FILELIST *
- fi
-done
diff --git a/doc/makepkg.8.in b/doc/makepkg.8.in
index d6a7994f..5f86f795 100644
--- a/doc/makepkg.8.in
+++ b/doc/makepkg.8.in
@@ -8,7 +8,7 @@ makepkg \- package build utility
a build-capable linux platform, wget, and some build scripts. The advantage
to a script-based build is that you only really do the work once. Once you
have the build script for a package, you just need to run makepkg and it
-will do the rest: download source files, check dependencies,
+will do the rest: download and validate source files, check dependencies,
configure the buildtime settings, build the package, install the package
into a temporary root, make customizations, generate meta-info, and package
the whole thing up for \fBpacman\fP to use.
@@ -31,20 +31,23 @@ the \fBabs\fP script included with pacman/makepkg.
.RS
.nf
pkgname=modutils
-pkgver=2.4.13
+pkgver=2.4.25
pkgrel=1
pkgdesc="Utilities for inserting and removing modules from the linux kernel"
url="http://www.kernel.org"
backup=(etc/modules.conf)
-depends=('glibc>=2.2.5' 'bash' 'zlib')
-source=(ftp://ftp.server.com/$pkgname-$pkgver.tar.gz modules.conf)
+depends=('mawk' 'bash' 'glibc' 'zlib')
+source=(ftp://ftp.kernel.org/pub/linux/utils/kernel/$pkgname/v2.4/$pkgname-$pkgver.tar.bz2 \\
+ modules.conf)
+md5sums=('2c0cca3ef6330a187c6ef4fe41ecaa4d' \\
+ '35175bee593a7cc7d6205584a94d8625')
build() {
cd $startdir/src/$pkgname-$pkgver
- ./configure --prefix=/usr
+ ./configure --prefix=/usr --enable-insmod-static
make || return 1
make prefix=$startdir/pkg/usr install
- # copy our custom modules.conf into the package root
+ mv $startdir/pkg/usr/sbin $startdir/pkg
mkdir -p $startdir/pkg/etc
cp ../modules.conf $startdir/pkg/etc
}
@@ -61,10 +64,14 @@ The line with \fIbackup=\fP specifies files that should be treated specially
when removing or upgrading packages. See \fBHANDLING CONFIG FILES\fP in
the \fIpacman\fP manpage for more information on this.
-The sixth line lists the dependencies for this package. In order to build/run
+The seventh line lists the dependencies for this package. In order to build/run
the package, all dependencies must be satisifed first. makepkg will check this
before attempting to build the package.
+The \fIsource\fP array tells makepkg which files to download/extract before compiling
+begins. The \fImd5sums\fP array provides md5sums for each of these files. These
+are used to validate the integrity of the source files.
+
Once your PKGBUILD is created, you can run \fImakepkg\fP from the build directory.
makepkg will then check dependencies and look for the source files required to
build. If some are missing it will attempt to download them, provided there is
@@ -193,7 +200,28 @@ This field contains an optional URL that is associated with the piece of softwar
being packaged. This is typically the project's website.
.TP
-.B backup
+.B install
+Specifies a special install script that is to be included in the package.
+This file should reside in the same directory as the PKGBUILD, and will be
+copied into the package by makepkg. It does not need to be included in the
+\fIsource\fP array. (eg, install=modutils.install)
+
+.TP
+.B source \fI(array)\fP
+The \fIsource\fP line is an array of source files required to build the
+package. Source files must reside in the same directory as the PKGBUILD
+file, unless they have a fully-qualified URL. Then if the source file
+does not already exist in /var/cache/pacman/src, the file is downloaded
+by wget.
+
+.TP
+.B groups \fI(array)\fP
+This is an array of symbolic names that represent groups of packages, allowing
+you to install multiple packages by requesting a single target. For example,
+one could install all KDE packages by installing the 'kde' group.
+
+.TP
+.B backup \fI(array)\fP
A space-delimited array of filenames (without a preceding slash). The
\fIbackup\fP line will be propagated to the package meta-info file for
pacman. This will designate all files listed there to be backed up if this
@@ -201,14 +229,7 @@ package is ever removed from a system. See \fBHANDLING CONFIG FILES\fP in
the \fIpacman\fP manpage for more information.
.TP
-.B install
-Specified a special install script that is to be included in the package.
-This file should reside in the same directory as the PKGBUILD, and will be
-copied into the package by makepkg. It does not need to be included in the
-\fIsource\fP array. (eg, install=modutils.install)
-
-.TP
-.B depends
+.B depends \fI(array)\fP
An array of packages that this package depends on to build and run. Packages
in this list should be surrounded with single quotes and contain at least the
package name. They can also include a version requirement of the form
@@ -217,18 +238,24 @@ package name. They can also include a version requirement of the form
See the PKGBUILD example above for an example of the \fIdepends\fP directive.
.TP
-.B conflicts
+.B conflicts \fI(array)\fP
An array of packages that will conflict with this package (ie, they cannot both
be installed at the same time). This directive follows the same format as
\fIdepends\fP except you cannot specify versions here, only package names.
.TP
-.B source
-The \fIsource\fP line is an array of source files required to build the
-package. Source files must reside in the same directory as the PKGBUILD
-file, unless they have a fully-qualified URL. Then if the source file
-does not already exist in /var/cache/pacman/src, the file is downloaded
-by wget.
+.B provides \fI(array)\fP
+An array of "virtual provisions" that this package provides. This allows a package
+to provide dependency names other than it's own package name. For example, the
+kernel-scsi and kernel-ide packages can each provide 'kernel' which allows packages
+to simply depend on 'kernel' rather than "kernel-scsi OR kernel-ide OR ..."
+
+.TP
+.B replaces \fI(array)\fP
+This is an array of packages that this package should replace, and can be used to handle
+renamed/combined packages. For example, if the kernel package gets renamed
+to kernel-ide, then subsequent 'pacman -Syu' calls will not pick up the upgrade, due
+to the differing package names. \fIreplaces\fP handles this.
.SH MAKEPKG OPTIONS
.TP
@@ -255,9 +282,20 @@ process if all of the dependencies aren't installed.
file already exists in the build directory. You can override this behaviour with
the \fB--force\fP switch.
.TP
+.B "\-g, \-\-genmd5"
+Download all source files (if required) and use \fImd5sum\fP to generate md5 hashes
+for each of them. You can then redirect the output into your PKGBUILD for source
+validation (makepkg -g >>PKGBUILD).
+.TP
+.B "\-h, \-\-help"
+Output syntax and commandline options.
+.TP
.B "\-i, \-\-install"
Install/Upgrade the package after a successful build.
.TP
+.B "\-n, \-\-nostrip"
+Do not strip binaries and libraries.
+.TP
.B "\-p <buildscript>"
Read the package script \fI<buildscript>\fP instead of the default (\fIPKGBUILD\fP).
.TP
diff --git a/doc/pacman.8.in b/doc/pacman.8.in
index 2113fc21..95b77154 100644
--- a/doc/pacman.8.in
+++ b/doc/pacman.8.in
@@ -96,6 +96,10 @@ Remove packages from the cache. When pacman downloads packages,
it saves them in \fI/var/cache/pacman/pkg\fP. If you need to free up
diskspace, you can remove these packages by using the --clean option.
.TP
+.B "\-g, \-\-groups"
+Display all the members for each package group specified. If no group
+names are provided, all groups and members will be listed.
+.TP
.B "\-s, \-\-search <string>"
This will search each package in the package list for names or descriptions
that contains <string>.
@@ -117,6 +121,10 @@ defined in \fI/etc/pacman.conf\fP. This should typically be used each
time you use \fB--sysupgrade\fP.
.SH QUERY OPTIONS
.TP
+.B "\-g, \-\-groups"
+Display all groups that a specified package is part of. If no package
+names are provided, all groups and members will be listed.
+.TP
.B "\-i, \-\-info"
Display information on a given package. If it is used with the \fB-p\fP
option then the .PKGINFO file will be printed.
@@ -179,15 +187,15 @@ Server = ftp://ftp.archlinux.org/current
Server = ftp://ftp.mirror.com/archlinux/current
[custom]
-Server = local:///home/pkgs
+Server = file:///home/pkgs
.fi
.RE
.SH CONFIG: OPTIONS
.TP
-.B "DBPath = /path/to/db/dir"
+.B "DBPath = path/to/db/dir"
Overrides the default location of the toplevel database directory. The default is
-\fI/var/lib/pacman\fP.
+\fIvar/lib/pacman\fP.
.TP
.B "IgnorePkg = <package> [package] ..."
Instructs pacman to ignore any upgrades for this package when performing a
@@ -199,13 +207,17 @@ Disables passive ftp connections when downloading packages. (aka Active Mode)
.B "NoUpgrade = <file> [file] ..."
All files listed with a \fBNoUpgrade\fP directive will never be touched during a package
install/upgrade. \fINote:\fP do not include the leading slash when specifying files.
+.TP
+.B "UseSyslog"
+Log action messages through syslog(). This will insert pacman log entries into your
+/var/log/messages or equivalent.
.SH CONFIG: REPOSITORIES
Each repository section defines a section name and at least one location where the packages
can be found. The section name is defined by the string within square brackets (eg, the two
above are 'current' and 'custom'). Locations are defined with the \fIServer\fP directive and
follow a URL naming structure. Currently only ftp is supported for remote servers. If you
-want to use a local directory, you can specify the full path with a 'local://' prefix, as
+want to use a local directory, you can specify the full path with a 'file://' prefix, as
shown above.
.SH USING YOUR OWN REPOSITORY
Let's say you have a bunch of custom packages in \fI/home/pkgs\fP and their respective PKGBUILD
diff --git a/etc/makepkg.conf b/etc/makepkg.conf
index b2d8a893..77e62936 100644
--- a/etc/makepkg.conf
+++ b/etc/makepkg.conf
@@ -10,21 +10,23 @@ export FTPAGENT="/usr/bin/wget --continue --passive-ftp --tries=3 --waitretry=3"
#export FTPAGENT="/usr/bin/snarf"
#export FTPAGENT="/usr/bin/lftpget -c"
-# Pentium Pro/Pentium II/Pentium III+/Pentium 4/Athlon optimized (but binaries
-# will run on any x86 system)
-#export CHOST="i686-pc-linux-gnu"
-#export CFLAGS="-mcpu=i686 -O2 -pipe"
-#export CXXFLAGS="-mcpu=i686 -O2 -pipe"
-
# Pentium Pro/Pentium II/Pentium III+/Pentium 4/Athlon exclusive (binaries
# will use the P6 instruction set and only run on P6+ systems)
export CHOST="i686-pc-linux-gnu"
export CFLAGS="-march=i686 -O2 -pipe"
export CXXFLAGS="-march=i686 -O2 -pipe"
+# Pentium Pro/Pentium II/Pentium III+/Pentium 4/Athlon optimized (but binaries
+# will run on any x86 system)
+#export CHOST="i686-pc-linux-gnu"
+#export CFLAGS="-mcpu=i686 -O2 -pipe"
+#export CXXFLAGS="-mcpu=i686 -O2 -pipe"
# SMP Systems
#export MAKEFLAGS="-j 2"
+# Enable fakeroot for building packages as a non-root user
+export USE_FAKEROOT="y"
+
# if you want your name to show up in the packages you build, set this.
#export PACKAGER="John Doe <john@doe.com>"
diff --git a/etc/pacman.conf b/etc/pacman.conf
index aacf95ba..a11b383d 100644
--- a/etc/pacman.conf
+++ b/etc/pacman.conf
@@ -8,9 +8,11 @@
# GENERAL OPTIONS
#
[options]
+UseSyslog
NoUpgrade = etc/passwd etc/group etc/shadow
-NoUpgrade = etc/fstab etc/rc.conf etc/rc.local
-NoUpgrade = etc/lilo.conf etc/raidtab
+NoUpgrade = etc/fstab etc/raidtab
+NoUpgrade = etc/rc.conf etc/rc.local
+NoUpgrade = etc/lilo.conf boot/grub/menu.lst
#IgnorePkg = lilo gcc
#
@@ -28,6 +30,20 @@ Server = ftp://gd.tuwien.ac.at/opsys/linux/archlinux/current
Server = ftp://saule.mintis.lt/pub/linux/current
Server = ftp://ftp.rez-gif.supelec.fr/pub/Linux/distrib/archlinux/current
+# The "unofficial" package set
+#
+[unofficial]
+Server = ftp://ftp.archlinux.org/unofficial
+Server = ftp://ftp.ibiblio.org/pub/linux/distributions/archlinux/unofficial
+Server = ftp://ftp.webtrek.com/pub/mirrors/archlinux/unofficial
+Server = ftp://ftp.mpi-sb.mpg.de/pub/linux/mirror/ftp.ibiblio.org/pub/Linux/distributions/archlinux/unofficial
+Server = ftp://ftp.oit.unc.edu/pub/Linux/distributions/archlinux/unofficial
+Server = ftp://ftp.tu-chemnitz.de/pub/linux/sunsite.unc-mirror/distributions/archlinux/unofficial
+Server = ftp://ftp.parrswood.net/Mirrors/ftp.archlinux.org/unofficial
+Server = ftp://gd.tuwien.ac.at/opsys/linux/archlinux/unofficial
+Server = ftp://saule.mintis.lt/pub/linux/unofficial
+Server = ftp://ftp.rez-gif.supelec.fr/pub/Linux/distrib/archlinux/unofficial
+
# If you use the 'stable' tree, you should disable the 'current'
# tree to avoid conflicts
#
@@ -43,26 +59,12 @@ Server = ftp://ftp.rez-gif.supelec.fr/pub/Linux/distrib/archlinux/current
#Server = ftp://saule.mintis.lt/pub/linux/stable
#Server = ftp://ftp.rez-gif.supelec.fr/pub/Linux/distrib/archlinux/stable
-# Uncomment this block to access the 'unofficial' package set
-#
-#[unofficial]
-#Server = ftp://ftp.ibiblio.org/pub/linux/distributions/archlinux/unofficial
-#Server = ftp://ftp.webtrek.com/pub/mirrors/archlinux/unofficial
-#Server = ftp://ftp.archlinux.org/unofficial
-#Server = ftp://ftp.mpi-sb.mpg.de/pub/linux/mirror/ftp.ibiblio.org/pub/Linux/distributions/archlinux/unofficial
-#Server = ftp://ftp.oit.unc.edu/pub/Linux/distributions/archlinux/unofficial
-#Server = ftp://ftp.tu-chemnitz.de/pub/linux/sunsite.unc-mirror/distributions/archlinux/unofficial
-#Server = ftp://ftp.parrswood.net/Mirrors/ftp.archlinux.org/unofficial
-#Server = ftp://gd.tuwien.ac.at/opsys/linux/archlinux/unofficial
-#Server = ftp://saule.mintis.lt/pub/linux/unofficial
-#Server = ftp://ftp.rez-gif.supelec.fr/pub/Linux/distrib/archlinux/unofficial
-
# Uncomment this block to access the 'unstable' package set
#
#[unstable]
+#Server = ftp://ftp.archlinux.org/unstable
#Server = ftp://ftp.ibiblio.org/pub/linux/distributions/archlinux/unstable
#Server = ftp://ftp.webtrek.com/pub/mirrors/archlinux/unstable
-#Server = ftp://ftp.archlinux.org/unstable
#Server = ftp://ftp.mpi-sb.mpg.de/pub/linux/mirror/ftp.ibiblio.org/pub/Linux/distributions/archlinux/unstable
#Server = ftp://ftp.oit.unc.edu/pub/Linux/distributions/archlinux/unstable
#Server = ftp://ftp.tu-chemnitz.de/pub/linux/sunsite.unc-mirror/distributions/archlinux/unstable
@@ -74,5 +76,5 @@ Server = ftp://ftp.rez-gif.supelec.fr/pub/Linux/distrib/archlinux/current
# An example of a custom package repository. See the pacman manpage for
# tips on creating your own repositories.
#[custom]
-#Server = local:///home/custompkgs
+#Server = file:///home/custompkgs
diff --git a/scripts/gensync b/scripts/gensync
index ef528543..e6bf8982 100755
--- a/scripts/gensync
+++ b/scripts/gensync
@@ -1,6 +1,26 @@
#!/bin/bash
+#
+# gensync
+#
+# Copyright (c) 2002-2003 by Judd Vinet <jvinet@zeroflux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+# USA.
+#
-myver='2.5.1'
+myver='2.6'
usage() {
echo "gensync $myver"
@@ -24,14 +44,15 @@ usage() {
db_write_entry()
{
- unset pkgname pkgver pkgrel
- unset depends conflicts
+ unset pkgname pkgver pkgrel pkgdesc
+ unset groups replaces provides depends conflicts
source $1 || return 1
cd /tmp/.gensync
mkdir $pkgname-$pkgver-$pkgrel
cd $pkgname-$pkgver-$pkgrel
# desc
- echo "%NAME%" >desc
+ : >desc
+ echo "%NAME%" >>desc
echo "$pkgname" >>desc
echo "" >>desc
echo "%VERSION%" >>desc
@@ -40,17 +61,43 @@ db_write_entry()
echo "%DESC%" >>desc
echo "$pkgdesc" >>desc
echo "" >>desc
+ if [ ${#groups[*]} -gt 0 ]; then
+ echo "%GROUPS%" >>desc
+ for it in "${groups[@]}"; do
+ echo "$it" >>desc
+ done
+ echo "" >>desc
+ fi
+ if [ ${#replaces[*]} -gt 0 ]; then
+ echo "%REPLACES%" >>desc
+ for it in "${replaces[@]}"; do
+ echo "$it" >>desc
+ done
+ echo "" >>desc
+ fi
# depends
- echo "%DEPENDS%" >depends
- for depend in "${depends[@]}"; do
- echo "$depend" >>depends
- done
- echo "" >>depends
- echo "%CONFLICTS%" >>depends
- for conflict in "${conflicts[@]}"; do
- echo "$conflict" >>depends
- done
- echo "" >>depends
+ : >depends
+ if [ ${#depends[*]} -gt 0 ]; then
+ echo "%DEPENDS%" >>depends
+ for it in "${depends[@]}"; do
+ echo "$it" >>depends
+ done
+ echo "" >>depends
+ fi
+ if [ ${#conflicts[*]} -gt 0 ]; then
+ echo "%CONFLICTS%" >>depends
+ for it in "${conflicts[@]}"; do
+ echo "$it" >>depends
+ done
+ echo "" >>depends
+ fi
+ if [ ${#provides[*]} -gt 0 ]; then
+ echo "%PROVIDES%" >>depends
+ for it in "${provides[@]}"; do
+ echo "$it" >>depends
+ done
+ echo "" >>depends
+ fi
}
if [ $# -lt 2 ]; then
diff --git a/scripts/makepkg b/scripts/makepkg
index 89e9ee22..a620d139 100755
--- a/scripts/makepkg
+++ b/scripts/makepkg
@@ -1,17 +1,68 @@
#!/bin/bash
-
-myver='2.5.1'
+#
+# makepkg
+#
+# Copyright (c) 2002-2003 by Judd Vinet <jvinet@zeroflux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+# USA.
+#
+
+myver='2.6'
startdir=`pwd`
+msg() {
+ echo "$1" >&2
+}
+
[ -f /etc/makepkg.conf ] && source /etc/makepkg.conf
+INFAKEROOT=
+if [ "$1" = "-F" ]; then
+ INFAKEROOT=1
+ shift
+fi
+
+if [ "`id -u`" != "0" ]; then
+ if [ "$USE_FAKEROOT" = "y" -o "$USE_FAKEROOT" = "Y" ]; then
+ if [ `type -p fakeroot` ]; then
+ msg "==> Entering fakeroot environment"
+ fakeroot -- $0 -F $@
+ exit $?
+ else
+ msg "==> WARNING: Fakeroot is not installed. Building as an unprivileged user"
+ msg "==> will result in non-root ownership of the packaged files."
+ msg "==> Install the fakeroot package to correctly build as a non-root"
+ msg "==> user."
+ msg ""
+ sleep 1
+ fi
+ else
+ msg "==> WARNING: Running makepkg as an unprivileged user will result in non-root"
+ msg "==> ownership of the packaged files. Try using the fakeroot"
+ msg "==> environment. (USE_FAKEROOT=y in makepkg.conf)"
+ msg ""
+ sleep 1
+ fi
+fi
+
+
strip_url() {
echo $1 | sed 's|^.*://.*/||g'
}
-msg() {
- echo $* >&2
-}
checkdeps() {
local missdep=`pacman -T $*`
@@ -50,31 +101,34 @@ usage() {
echo "makepkg version $myver"
echo "usage: $0 [options]"
echo "options:"
+ echo " -b, --builddeps Build missing dependencies from source"
echo " -c, --clean Clean up work files after build"
echo " -C, --cleancache Clean up source files from the cache"
- echo " -s, --syncdeps Install missing dependencies with pacman"
- echo " -b, --builddeps Build missing dependencies from source"
echo " -d, --nodeps Skip all dependency checks"
- echo " -i, --install Install package after successful build"
echo " -f, --force Overwrite existing package"
- echo " -w <destdir> Write package to <destdir> instead of the working dir"
- echo " -p <buildscript> Use an alternate build script (instead of PKGBUILD)"
+ echo " -g, --genmd5 Generate MD5sums for source files"
echo " -h, --help This help"
+ echo " -i, --install Install package after successful build"
+ echo " -n, --nostrip Do not strip binaries/libraries"
+ echo " -p <buildscript> Use an alternate build script (instead of PKGBUILD)"
+ echo " -s, --syncdeps Install missing dependencies with pacman"
+ echo " -w <destdir> Write package to <destdir> instead of the working dir"
echo
echo " if -p is not specified, makepkg will look for a PKGBUILD"
echo " file in the current directory."
echo
- exit 0
}
# Options
CLEANUP=0
CLEANCACHE=0
INSTALL=0
+GENMD5=0
DEP_BIN=0
DEP_SRC=0
NODEPS=0
FORCE=0
+NOSTRIP=0
PKGDEST=$startdir
BUILDSCRIPT="./PKGBUILD"
@@ -87,12 +141,18 @@ while [ "$#" -ne "0" ]; do
--nodeps) NODEPS=1 ;;
--install) INSTALL=1 ;;
--force) FORCE=1 ;;
+ --nostrip) NOSTRIP=1 ;;
+ --genmd5) GENMD5=1 ;;
+ --help)
+ usage
+ exit 0
+ ;;
--*)
usage
exit 1
;;
-*)
- while getopts "cCsbdifp:w:-" opt; do
+ while getopts "cCsbdhifgnp:w:-" opt; do
case $opt in
c) CLEANUP=1 ;;
C) CLEANCACHE=1 ;;
@@ -100,9 +160,15 @@ while [ "$#" -ne "0" ]; do
b) DEP_SRC=1 ;;
d) NODEPS=1 ;;
i) INSTALL=1 ;;
+ g) GENMD5=1 ;;
f) FORCE=1 ;;
+ n) NOSTRIP=1 ;;
w) PKGDEST=$OPTARG ;;
p) BUILDSCRIPT=$OPTARG ;;
+ h)
+ usage
+ exit 0
+ ;;
-)
OPTIND=0
break
@@ -122,13 +188,18 @@ while [ "$#" -ne "0" ]; do
done
if [ "$CLEANCACHE" = "1" ]; then
- msg "==> Cleaning up source files from the cache"
- rm -rf /var/cache/pacman/src/*
- exit 0
+ if [ "`id -u`" = "0" -a "$INFAKEROOT" != "1" ]; then
+ msg "==> Cleaning up source files from the cache."
+ rm -rf /var/cache/pacman/src/*
+ exit 0
+ else
+ msg "==> You must be root to clean the cache."
+ exit 1
+ fi
fi
-unset pkgname pkgver pkgrel pkgdesc url
-unset depends conflicts backup source install build
+unset pkgname pkgver pkgrel pkgdesc url groups provides md5sums
+unset replaces depends conflicts backup source install build
umask 0022
if [ ! -f $BUILDSCRIPT ]; then
@@ -148,11 +219,13 @@ if [ `echo $pkgrel | grep '-'` ]; then
exit 1
fi
-if [ -f $PKGDEST/${pkgname}-${pkgver}-${pkgrel}.pkg.tar.gz -a "$FORCE" = "0" ]; then
+if [ -f $PKGDEST/${pkgname}-${pkgver}-${pkgrel}.pkg.tar.gz -a "$FORCE" = "0" -a "$GENMD5" = "0" ]; then
msg "==> ERROR: a package has already been built. (use -f to overwrite)"
exit 1
fi
+msg "==> Making package: $pkgname (`date`)"
+
unset deplist
if [ `type -p pacman` -a "$NODEPS" = "0" ]; then
msg "==> Checking Dependencies..."
@@ -210,21 +283,19 @@ else
msg "==> WARNING: pacman was not found in PATH. skipping dependency checks."
fi
-d=`date`
cd $startdir
-msg "==> Making package $pkgname ($d)"
# extract source
-msg "==> Acquiring/Extracting Sources..."
+msg "==> Retrieving Sources..."
mkdir -p src
cd $startdir/src
for netfile in ${source[@]}; do
file=`strip_url $netfile`
if [ -f ../$file ]; then
- msg "==> Found $file in build dir"
+ msg " |=> Found $file in build dir"
cp ../$file .
elif [ -f /var/cache/pacman/src/$file ]; then
- msg "==> Using local copy of $file"
+ msg " |=> Using local copy of $file"
cp /var/cache/pacman/src/$file .
else
# check for a download utility
@@ -245,39 +316,108 @@ for netfile in ${source[@]}; do
msg "==> Aborting..."
exit 1
fi
- msg "==> Downloading $file"
+ msg " |=> Downloading $file"
$FTPAGENT $netfile 2>&1
if [ ! -f $file ]; then
msg "==> ERROR: Failed to download $file"
msg "==> Aborting..."
exit 1
fi
- mkdir -p /var/cache/pacman/src && cp $file /var/cache/pacman/src
+ if [ "`id -u`" = "0" -a "$INFAKEROOT" != "1" ]; then
+ mkdir -p /var/cache/pacman/src && cp $file /var/cache/pacman/src
+ else
+ cp $file ..
+ fi
fi
- unset cmd
- case $file in
- *.tar.gz|*.tar.Z|*.tgz)
- cmd="tar --use-compress-program=gzip -xf $file" ;;
- *.tar.bz2)
- cmd="tar --use-compress-program=bzip2 -xf $file" ;;
- *.tar)
- cmd="tar -xf $file" ;;
- *.zip)
- cmd="unzip -qq $file" ;;
- *.gz)
- cmd="gunzip $file" ;;
- esac
- if [ "$cmd" != "" ]; then
- msg "==> $cmd"
- $cmd
- if [ $? -ne 0 ]; then
- msg "==> ERROR: Failed to extract $file"
- msg "==> Aborting..."
- exit 1
+ if [ "$GENMD5" = "0" ]; then
+ unset cmd
+ case $file in
+ *.tar.gz|*.tar.Z|*.tgz)
+ cmd="tar --use-compress-program=gzip -xf $file" ;;
+ *.tar.bz2)
+ cmd="tar --use-compress-program=bzip2 -xf $file" ;;
+ *.tar)
+ cmd="tar -xf $file" ;;
+ *.zip)
+ cmd="unzip -qq $file" ;;
+ *.gz)
+ cmd="gunzip $file" ;;
+ esac
+ if [ "$cmd" != "" ]; then
+ msg " |=> $cmd"
+ $cmd
+ if [ $? -ne 0 ]; then
+ msg "==> ERROR: Failed to extract $file"
+ msg "==> Aborting..."
+ exit 1
+ fi
fi
fi
done
+if [ "$GENMD5" = "1" ]; then
+ if [ ! `type -p md5sum` ]; then
+ msg "==> ERROR: Cannot find the md5sum program."
+ exit 1
+ fi
+ msg "==> Generating MD5sums for source files"
+ msg ""
+ ct=0
+ numsrc=${#source[@]}
+ for netfile in ${source[@]}; do
+ file=`strip_url $netfile`
+ sum=`md5sum $file | cut -d' ' -f 1`
+ if [ $ct -eq 0 ]; then
+ echo -n "md5sums=("
+ else
+ echo -ne "\t"
+ fi
+ echo -n "'$sum'"
+ ct=$(($ct+1))
+ if [ $ct -eq $numsrc ]; then
+ echo ')'
+ else
+ echo ' \'
+ fi
+ done
+ msg ""
+ exit 0
+fi
+
+# MD5 Validation
+if [ ${#md5sums[@]} -ne ${#source[@]} ]; then
+ msg "==> WARNING: MD5sums are missing or incomplete. Cannot verify source integrity."
+# sleep 1
+elif [ `type -p md5sum` ]; then
+ msg "==> Validating source files with MD5sums"
+ errors=0
+ idx=0
+ for netfile in ${source[@]}; do
+ file=`strip_url $netfile`
+ echo -n " |=> $file ... " >&2
+ echo "${md5sums[$idx]} $file" | md5sum -c - >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ echo "FAILED" >&2
+ errors=1
+ else
+ echo "Passed" >&2
+ fi
+ idx=$(($idx+1))
+ done
+ if [ $errors -gt 0 ]; then
+ msg "==> ERROR: One or more files did not pass the validity check!"
+ exit 1
+ fi
+else
+ msg "==> WARNING: The md5sum program is missing. Cannot verify source files!"
+ sleep 1
+fi
+
+if [ "`id -u`" = "0" ]; then
+ # chown all source files to root.root
+ chown -R root.root $startdir/src
+fi
+
# check for existing pkg directory
if [ -d $startdir/pkg ]; then
msg "==> Removing existing pkg directory..."
@@ -286,7 +426,7 @@ fi
mkdir -p $startdir/pkg
# build
-msg "==> Building Package..."
+msg "==> Starting build()..."
build 2>&1
if [ $? -gt 0 ]; then
msg "==> Build Failed. Aborting..."
@@ -330,15 +470,18 @@ if [ -d pkg/usr/man ]; then
done
fi
-# strip binaries
cd $startdir
-msg "==> Stripping debugging symbols from libraries..."
-find pkg/{,usr,usr/local,opt/*}/lib -type f -exec /usr/bin/strip --strip-debug '{}' ';' 2>&1
-msg "==> Stripping symbols from binaries..."
-find pkg/{,usr,usr/local,opt/*}/{bin,sbin} -type f -exec /usr/bin/strip '{}' ';' 2>&1
+
+# strip binaries
+if [ "$NOSTRIP" = "0" ]; then
+ msg "==> Stripping debugging symbols from libraries..."
+ find pkg/{,usr,usr/local,opt/*}/lib -type f -exec /usr/bin/strip --strip-debug '{}' \; 2>&1
+ msg "==> Stripping symbols from binaries..."
+ find pkg/{,usr,usr/local,opt/*}/{bin,sbin} -type f -exec /usr/bin/strip '{}' \; 2>&1
+fi
# get some package meta info
-builddate=`date -u "+%a %b %d %k:%M:%S %Y"`
+builddate=`LC_ALL= ; date -u "+%a %b %d %k:%M:%S %Y"`
if [ "$PACKAGER" != "" ]; then
packager="$PACKAGER"
else
@@ -360,14 +503,23 @@ echo "builddate = $builddate" >>.PKGINFO
echo "packager = $packager" >>.PKGINFO
echo "size = $size" >>.PKGINFO
-for depend in "${depends[@]}"; do
- echo "depend = $depend" >>.PKGINFO
+for it in "${replaces[@]}"; do
+ echo "replaces = $it" >>.PKGINFO
+done
+for it in "${groups[@]}"; do
+ echo "group = $it" >>.PKGINFO
+done
+for it in "${depends[@]}"; do
+ echo "depend = $it" >>.PKGINFO
+done
+for it in "${conflicts[@]}"; do
+ echo "conflict = $it" >>.PKGINFO
done
-for conflict in "${conflicts[@]}"; do
- echo "conflict = $conflict" >>.PKGINFO
+for it in "${provides[@]}"; do
+ echo "provides = $it" >>.PKGINFO
done
-for bakfile in "${backup[@]}"; do
- echo "backup = $bakfile" >>.PKGINFO
+for it in "${backup[@]}"; do
+ echo "backup = $it" >>.PKGINFO
done
# check for an install script
@@ -377,9 +529,11 @@ if [ "$install" != "" ]; then
fi
# build a filelist
-msg "==> Building filelist..."
+msg "==> Generating .FILELIST file..."
cd $startdir/pkg
-tar cv * >/dev/null 2>.FILELIST
+tar cv * >/dev/null 2>.FILELIST.tmp
+cat .FILELIST.tmp | sort >.FILELIST
+rm -f .FILELIST.tmp
# tar it up
msg "==> Compressing package..."
@@ -389,7 +543,7 @@ if [ -f $startdir/pkg/.INSTALL ]; then
else
cmd="tar czvf $PKGDEST/$pkgname-$pkgver-$pkgrel.pkg.tar.gz .PKGINFO .FILELIST *"
fi
-$cmd >../filelist
+$cmd | sort >../filelist
cd $startdir
if [ "$CLEANUP" = "1" ]; then
@@ -397,7 +551,7 @@ if [ "$CLEANUP" = "1" ]; then
rm -rf src pkg filelist
fi
-msg "==> Finished making $pkgname (`date`)"
+msg "==> Finished making: $pkgname (`date`)"
if [ "$INSTALL" = "1" ]; then
msg "==> Running pacman --upgrade"
diff --git a/scripts/makeworld b/scripts/makeworld
index 94a522e2..aee9792c 100755
--- a/scripts/makeworld
+++ b/scripts/makeworld
@@ -1,102 +1,130 @@
#!/bin/bash
+#
+# makeworld
+#
+# Copyright (c) 2002-2003 by Judd Vinet <jvinet@zeroflux.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+# USA.
+#
toplevel=`pwd`
-version="2.5.1"
+version="2.6"
usage() {
- echo "makeworld version $version"
- echo "usage: $0 [options] <destdir> <category> [category] ..."
- echo "options:"
- echo " -b, --builddeps Build missing dependencies from source"
- echo " -c, --clean Clean up work files after build"
- echo " -d, --nodeps Skip all dependency checks"
- echo " -f, --force Overwrite existing packages"
- echo " -i, --install Install package after successful build"
- echo " -h, --help This help"
- echo " -s, --syncdeps Install missing dependencies with pacman"
- echo
- echo " where <category> is one or more directory names under the ABS root"
- echo " eg: makeworld -c /packages base lib editors"
- echo
- echo " this should be run from the toplevel directory of ABS (usually /usr/abs)"
+ echo "makeworld version $version"
+ echo "usage: $0 [options] <destdir> <category> [category] ..."
+ echo "options:"
+ echo " -b, --builddeps Build missing dependencies from source"
+ echo " -c, --clean Clean up work files after build"
+ echo " -d, --nodeps Skip all dependency checks"
+ echo " -f, --force Overwrite existing packages"
+ echo " -i, --install Install package after successful build"
+ echo " -h, --help This help"
+ echo " -s, --syncdeps Install missing dependencies with pacman"
+ echo
+ echo " where <category> is one or more directory names under the ABS root"
+ echo " eg: makeworld -c /packages base lib editors"
+ echo
+ echo " this should be run from the toplevel directory of ABS (usually /usr/abs)"
}
-if [ $# -lt 2 -o "$1" = "--help" -o "$1" = "-h" ]; then
- usage
- exit 1
+if [ $# -lt 2 ]; then
+ usage
+ exit 1
fi
MAKEPKG_OPTS=
for arg in $*; do
- case $arg in
- --clean) MAKEPKG_OPTS="$MAKEPKG_OPTS -c" ;;
- --install) MAKEPKG_OPTS="$MAKEPKG_OPTS -i" ;;
- --syncdeps) MAKEPKG_OPTS="$MAKEPKG_OPTS -s" ;;
- --builddeps) MAKEPKG_OPTS="$MAKEPKG_OPTS -b" ;;
- --nodeps) MAKEPKG_OPTS="$MAKEPKG_OPTS -d" ;;
- --force) MAKEPKG_OPTS="$MAKEPKG_OPTS -f" ;;
- --*)
- usage
- exit 1
- ;;
- -*)
- while getopts "cisbdf-" opt; do
- case $opt in
- c) MAKEPKG_OPTS="$MAKEPKG_OPTS -c" ;;
- i) MAKEPKG_OPTS="$MAKEPKG_OPTS -i" ;;
- s) MAKEPKG_OPTS="$MAKEPKG_OPTS -s" ;;
- b) MAKEPKG_OPTS="$MAKEPKG_OPTS -b" ;;
- d) MAKEPKG_OPTS="$MAKEPKG_OPTS -d" ;;
- f) MAKEPKG_OPTS="$MAKEPKG_OPTS -f" ;;
- -)
- OPTIND=0
- break
- ;;
- esac
- done
- ;;
- *)
- dest=$arg
- shift
- break
- ;;
- esac
- shift
- if [ "$dest" != "" ]; then
- break;
- fi
+ case $arg in
+ --clean) MAKEPKG_OPTS="$MAKEPKG_OPTS -c" ;;
+ --install) MAKEPKG_OPTS="$MAKEPKG_OPTS -i" ;;
+ --syncdeps) MAKEPKG_OPTS="$MAKEPKG_OPTS -s" ;;
+ --builddeps) MAKEPKG_OPTS="$MAKEPKG_OPTS -b" ;;
+ --nodeps) MAKEPKG_OPTS="$MAKEPKG_OPTS -d" ;;
+ --force) MAKEPKG_OPTS="$MAKEPKG_OPTS -f" ;;
+ --help)
+ usage
+ exit 0
+ ;;
+ --*)
+ usage
+ exit 1
+ ;;
+ -*)
+ while getopts "chisbdf-" opt; do
+ case $opt in
+ c) MAKEPKG_OPTS="$MAKEPKG_OPTS -c" ;;
+ i) MAKEPKG_OPTS="$MAKEPKG_OPTS -i" ;;
+ s) MAKEPKG_OPTS="$MAKEPKG_OPTS -s" ;;
+ b) MAKEPKG_OPTS="$MAKEPKG_OPTS -b" ;;
+ d) MAKEPKG_OPTS="$MAKEPKG_OPTS -d" ;;
+ f) MAKEPKG_OPTS="$MAKEPKG_OPTS -f" ;;
+ h)
+ usage
+ exit 0
+ ;;
+ -)
+ OPTIND=0
+ break
+ ;;
+ esac
+ done
+ ;;
+ *)
+ dest=$arg
+ shift
+ break
+ ;;
+ esac
+ shift
+ if [ "$dest" != "" ]; then
+ break
+ fi
done
if [ "$dest" = "" ]; then
- usage
- exit 1
+ usage
+ exit 1
fi
sd=`date +"[%b %d %H:%M]"`
for category in $*; do
- for port in `find $toplevel/$category -type d -maxdepth 1 -mindepth 1 | sort`; do
- cd $port
- if [ -f PKGBUILD ]; then
- . PKGBUILD
- buildstatus=0
- if [ ! -f $dest/$pkgname-$pkgver-$pkgrel.pkg.tar.gz ]; then
- makepkg $MAKEPKG_OPTS -w $dest 2>>$toplevel/makepkg.log
- if [ $? -gt 0 ]; then
- buildstatus=2
- else
- buildstatus=1
- fi
- fi
- d=`date +"[%b %d %H:%M]"`
- echo -n "$d " >>$toplevel/build.log
- case $buildstatus in
- 0) echo "$pkgname already built -- skipping" >>$toplevel/build.log ;;
- 1) echo "$pkgname was built successfully" >>$toplevel/build.log ;;
- 2) echo "$pkgname build failed" >>$toplevel/build.log ;;
- esac
- fi
- done
+ for port in `find $toplevel/$category -type d -maxdepth 1 -mindepth 1 | sort`; do
+ cd $port
+ if [ -f PKGBUILD ]; then
+ . PKGBUILD
+ buildstatus=0
+ if [ ! -f $dest/$pkgname-$pkgver-$pkgrel.pkg.tar.gz ]; then
+ makepkg $MAKEPKG_OPTS -w $dest 2>>$toplevel/makepkg.log
+ if [ $? -gt 0 ]; then
+ buildstatus=2
+ else
+ buildstatus=1
+ fi
+ fi
+ d=`date +"[%b %d %H:%M]"`
+ echo -n "$d " >>$toplevel/build.log
+ case $buildstatus in
+ 0) echo "$pkgname already built -- skipping" >>$toplevel/build.log ;;
+ 1) echo "$pkgname was built successfully" >>$toplevel/build.log ;;
+ 2) echo "$pkgname build failed" >>$toplevel/build.log ;;
+ esac
+ fi
+ done
done
ed=`date +"[%b %d %H:%M]"`
@@ -104,3 +132,4 @@ echo "makeworld complete." >>$toplevel/build.log
echo " started: $sd" >>$toplevel/build.log
echo " finished: $ed" >>$toplevel/build.log
+exit 0
diff --git a/src/convertdb.c b/src/convertdb.c
index d337dcca..0a414e54 100644
--- a/src/convertdb.c
+++ b/src/convertdb.c
@@ -1,5 +1,5 @@
/*
- * pacman
+ * convertdb.c
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*
diff --git a/src/db.c b/src/db.c
index bf7be9f9..aea78ccb 100644
--- a/src/db.c
+++ b/src/db.c
@@ -1,5 +1,5 @@
/*
- * pacman
+ * db.c
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*
@@ -29,13 +29,7 @@
#include "util.h"
#include "db.h"
-/* Verify database integrity and build a list of
- * installed packages
- *
- * returns: 0 on success
- * 1 if db is not initialized
- * 2 if db is corrupt
- */
+/* Open a database and return a pacdb_t handle */
pacdb_t* db_open(char *root, char *pkgdir, char *treename)
{
pacdb_t *db = NULL;
@@ -111,7 +105,7 @@ PMList* db_loadpkgs(pacdb_t *db, PMList *pkgcache)
cache = list_add(cache, arr[i]);
}
- free(arr);
+ FREE(arr);
return(cache);
}
@@ -216,6 +210,11 @@ pkginfo_t* db_read(pacdb_t *db, struct dirent *ent, unsigned int inforeq)
return(NULL);
}
trim(info->desc);
+ } else if(!strcmp(line, "%GROUPS%")) {
+ while(fgets(line, 512, fp) && strlen(trim(line))) {
+ char *s = strdup(line);
+ info->groups = list_add(info->groups, s);
+ }
} else if(!strcmp(line, "%URL%")) {
if(fgets(info->url, sizeof(info->url), fp) == NULL) {
return(NULL);
@@ -243,6 +242,14 @@ pkginfo_t* db_read(pacdb_t *db, struct dirent *ent, unsigned int inforeq)
}
trim(tmp);
info->size = atol(tmp);
+ } else if(!strcmp(line, "%REPLACES%")) {
+ /* the REPLACES tag is special -- it only appears in sync repositories,
+ * not the local one.
+ */
+ while(fgets(line, 512, fp) && strlen(trim(line))) {
+ char *s = strdup(line);
+ info->replaces = list_add(info->replaces, s);
+ }
}
}
fclose(fp);
@@ -303,6 +310,12 @@ pkginfo_t* db_read(pacdb_t *db, struct dirent *ent, unsigned int inforeq)
info->conflicts = list_add(info->conflicts, s);
}
}
+ if(!strcmp(line, "%PROVIDES%")) {
+ while(fgets(line, 512, fp) && strlen(trim(line))) {
+ char *s = strdup(line);
+ info->provides = list_add(info->provides, s);
+ }
+ }
}
fclose(fp);
}
@@ -347,6 +360,11 @@ int db_write(pacdb_t *db, pkginfo_t *info)
fprintf(fp, "%s\n\n", info->version);
fputs("%DESC%\n", fp);
fprintf(fp, "%s\n\n", info->desc);
+ fputs("%GROUPS%\n", fp);
+ for(lp = info->groups; lp; lp = lp->next) {
+ fprintf(fp, "%s\n", (char*)lp->data);
+ }
+ fprintf(fp, "\n");
fputs("%URL%\n", fp);
fprintf(fp, "%s\n\n", info->url);
fputs("%BUILDDATE%\n", fp);
@@ -400,6 +418,11 @@ int db_write(pacdb_t *db, pkginfo_t *info)
fprintf(fp, "%s\n", (char*)lp->data);
}
fprintf(fp, "\n");
+ fputs("%PROVIDES%\n", fp);
+ for(lp = info->provides; lp; lp = lp->next) {
+ fprintf(fp, "%s\n", (char*)lp->data);
+ }
+ fprintf(fp, "\n");
fclose(fp);
/* INSTALL */
@@ -426,7 +449,6 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root)
*
pkginfo_t *info = NULL;
char *dbstr = NULL;
- vprint("Checking database against targets...\n");
rewinddir(db->dir);
while((info = db_scan(db, NULL, INFRQ_DESC | INFRQ_FILES)) != NULL) {
for(i = info->files; i; i = i->next) {
@@ -453,7 +475,6 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root)
}*/
/* CHECK 2: check every target against every target */
- /* orelien - vprint("Checking targets against targets...\n"); */
for(i = targets; i; i = i->next) {
pkginfo_t *p1 = (pkginfo_t*)i->data;
for(j = i; j; j = j->next) {
@@ -480,7 +501,6 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root)
}
/* CHECK 3: check every target against the filesystem */
- /* orelien - vprint("Checking targets against filesystem...\n"); */
for(i = targets; i; i = i->next) {
pkginfo_t *p = (pkginfo_t*)i->data;
pkginfo_t *dbpkg = NULL;
@@ -509,4 +529,72 @@ PMList* db_find_conflicts(pacdb_t *db, PMList *targets, char *root)
return(conflicts);
}
+PMList *whatprovides(pacdb_t *db, char* package)
+{
+ PMList *pkgs, *i = NULL;
+ pkginfo_t *info;
+
+ rewinddir(db->dir);
+ while((info = db_scan(db, NULL, INFRQ_DESC | INFRQ_DEPENDS)) != NULL) {
+ if(is_in(package, info->provides)) {
+ i = list_add(i, strdup(info->name));
+ }
+ freepkg(info);
+ }
+ pkgs = list_sort(i);
+ list_free(i);
+
+ return(pkgs);
+}
+
+/*
+ * return a list of all groups present in *db
+ *
+ */
+PMList *find_groups(pacdb_t *db)
+{
+ PMList *groups, *i = NULL;
+ PMList *lp = NULL;
+ pkginfo_t *info;
+
+ rewinddir(db->dir);
+ while((info = db_scan(db, NULL, INFRQ_DESC)) != NULL) {
+ for(lp = info->groups; lp; lp = lp->next) {
+ if(!is_in((char*)lp->data, i)) {
+ i = list_add(i, strdup((char*)lp->data));
+ }
+ }
+ freepkg(info);
+ }
+ groups = list_sort(i);
+ list_free(i);
+
+ return(groups);
+}
+
+/*
+ * return a list of all members of the specified group
+ *
+ */
+PMList *pkg_ingroup(pacdb_t *db, char *group)
+{
+ PMList *pkg, *i = NULL;
+ PMList *lp = NULL;
+ pkginfo_t *info;
+
+ rewinddir(db->dir);
+ while((info = db_scan(db, NULL, INFRQ_DESC)) != NULL) {
+ for(lp = info->groups; lp; lp = lp->next) {
+ if(!strcmp((char*)lp->data, group)) {
+ i = list_add(i, strdup(info->name));
+ }
+ }
+ freepkg(info);
+ }
+ pkg = list_sort(i);
+ list_free(i);
+
+ return(pkg);
+}
+
/* vim: set ts=2 sw=2 noet: */
diff --git a/src/db.h b/src/db.h
index 11404134..8f1424ba 100644
--- a/src/db.h
+++ b/src/db.h
@@ -1,5 +1,5 @@
/*
- * pacman
+ * db.h
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*
@@ -42,6 +42,9 @@ pkginfo_t* db_scan(pacdb_t *db, char *target, unsigned int inforeq);
pkginfo_t* db_read(pacdb_t *db, struct dirent *ent, unsigned int inforeq);
int db_write(pacdb_t *db, pkginfo_t *info);
PMList* db_find_conflicts(pacdb_t *db, PMList* targets, char *root);
+PMList *whatprovides(pacdb_t *db, char* package);
+PMList *find_groups(pacdb_t *db);
+PMList *pkg_ingroup(pacdb_t *db, char *group);
#endif
/* vim: set ts=2 sw=2 noet: */
diff --git a/src/list.c b/src/list.c
index dfb8f630..37f96530 100644
--- a/src/list.c
+++ b/src/list.c
@@ -1,5 +1,5 @@
/*
- * pacman
+ * list.c
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*
@@ -174,7 +174,9 @@ PMList *list_sort(PMList *list)
lp = list_add(lp, strdup(arr[i]));
}
- free(arr);
+ if(arr) {
+ free(arr);
+ }
return(lp);
}
diff --git a/src/list.h b/src/list.h
index edfc6f97..16c7c19d 100644
--- a/src/list.h
+++ b/src/list.h
@@ -1,5 +1,5 @@
/*
- * pacman
+ * list.h
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*
diff --git a/src/package.c b/src/package.c
index d41e1d85..b4a26387 100644
--- a/src/package.c
+++ b/src/package.c
@@ -1,7 +1,7 @@
/*
- * pacman
+ * package.c
*
- * Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
+ * Copyright (c) 2002-2003 by Judd Vinet <jvinet@zeroflux.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -181,6 +181,8 @@ int parse_descfile(char *descfile, pkginfo_t *info, PMList **backup, int output)
strncpy(info->version, ptr, sizeof(info->version));
} else if(!strcmp(key, "PKGDESC")) {
strncpy(info->desc, ptr, sizeof(info->desc));
+ } else if(!strcmp(key, "GROUP")) {
+ info->groups = list_add(info->groups, strdup(ptr));
} else if(!strcmp(key, "URL")) {
strncpy(info->url, ptr, sizeof(info->url));
} else if(!strcmp(key, "BUILDDATE")) {
@@ -193,15 +195,16 @@ int parse_descfile(char *descfile, pkginfo_t *info, PMList **backup, int output)
char tmp[32];
strncpy(tmp, ptr, sizeof(tmp));
info->size = atol(tmp);
- } else if(!strcmp(key, "DEPEND")) {
- char *s = strdup(ptr);
- info->depends = list_add(info->depends, s);
+ } else if(!strcmp(key, "DEPEND")) {
+ info->depends = list_add(info->depends, strdup(ptr));
} else if(!strcmp(key, "CONFLICT")) {
- char *s = strdup(ptr);
- info->conflicts = list_add(info->conflicts, s);
+ info->conflicts = list_add(info->conflicts, strdup(ptr));
+ } else if(!strcmp(key, "REPLACES")) {
+ info->replaces = list_add(info->replaces, strdup(ptr));
+ } else if(!strcmp(key, "PROVIDES")) {
+ info->provides = list_add(info->provides, strdup(ptr));
} else if(!strcmp(key, "BACKUP")) {
- char *s = strdup(ptr);
- bak = list_add(bak, s);
+ bak = list_add(bak, strdup(ptr));
} else {
fprintf(stderr, "%s: syntax error in description file line %d\n",
info->name[0] != '\0' ? info->name : "error", linenum);
@@ -235,6 +238,9 @@ pkginfo_t* newpkg()
pkg->files = NULL;
pkg->backup = NULL;
pkg->depends = NULL;
+ pkg->groups = NULL;
+ pkg->provides = NULL;
+ pkg->replaces = NULL;
return(pkg);
}
@@ -250,6 +256,9 @@ void freepkg(pkginfo_t *pkg)
list_free(pkg->depends);
list_free(pkg->conflicts);
list_free(pkg->requiredby);
+ list_free(pkg->groups);
+ list_free(pkg->provides);
+ list_free(pkg->replaces);
FREE(pkg);
return;
}
@@ -298,24 +307,30 @@ void dump_pkg(pkginfo_t *info)
return;
}
- printf("Name : %s\n", info->name);
- printf("Version : %s\n", info->version);
- printf("Packager : %s\n", info->packager);
- printf("URL: : %s\n", info->url);
- printf("Size : %ld\n", info->size);
- printf("Build Date : %s %s\n", info->builddate, strlen(info->builddate) ? "UTC" : "");
- printf("Install Date : %s %s\n", info->installdate, strlen(info->installdate) ? "UTC" : "");
- printf("Install Script: %s\n", (info->scriptlet ? "yes" : "no"));
+ printf("Name : %s\n", info->name);
+ printf("Version : %s\n", info->version);
+ pm = list_sort(info->groups);
+ list_display("Groups : ", pm);
+ FREE(pm);
+ printf("Packager : %s\n", info->packager);
+ printf("URL : %s\n", (info->url ? info->url : "None"));
+ printf("Size : %ld\n", info->size);
+ printf("Build Date : %s %s\n", info->builddate, strlen(info->builddate) ? "UTC" : "");
+ printf("Install Date : %s %s\n", info->installdate, strlen(info->installdate) ? "UTC" : "");
+ printf("Install Script : %s\n", (info->scriptlet ? "Yes" : "No"));
+ pm = list_sort(info->provides);
+ list_display("Provides : ", pm);
+ FREE(pm);
pm = list_sort(info->depends);
- list_display("Depends On : ", pm);
+ list_display("Depends On : ", pm);
FREE(pm);
pm = list_sort(info->requiredby);
- list_display("Required By : ", pm);
+ list_display("Required By : ", pm);
FREE(pm);
pm = list_sort(info->conflicts);
- list_display("Conflicts With: ", pm);
+ list_display("Conflicts With : ", pm);
FREE(pm);
- printf("Description : %s\n", info->desc);
+ printf("Description : %s\n", info->desc);
}
/* vim: set ts=2 sw=2 noet: */
diff --git a/src/package.h b/src/package.h
index 72b015c3..91d87e12 100644
--- a/src/package.h
+++ b/src/package.h
@@ -1,5 +1,5 @@
/*
- * pacman
+ * package.h
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*
@@ -41,11 +41,14 @@ typedef struct __pkginfo_t {
char packager[64];
unsigned long size;
unsigned short scriptlet;
+ PMList *replaces;
+ PMList *groups;
PMList *files;
PMList *backup;
PMList *depends;
PMList *requiredby;
PMList *conflicts;
+ PMList *provides;
} pkginfo_t;
typedef struct __depend_t {
diff --git a/src/pacman.c b/src/pacman.c
index 35421ff5..d393914b 100644
--- a/src/pacman.c
+++ b/src/pacman.c
@@ -1,5 +1,5 @@
/*
- * pacman
+ * pacman.c
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*
@@ -33,6 +33,7 @@
#include <time.h>
#include <getopt.h>
#include <zlib.h>
+#include <syslog.h>
#include <libtar.h>
/* pacman */
#include "rpmvercmp.h"
@@ -72,10 +73,12 @@ unsigned short pmo_s_downloadonly = 0;
unsigned short pmo_s_sync = 0;
unsigned short pmo_s_search = 0;
unsigned short pmo_s_clean = 0;
+unsigned short pmo_group = 0;
/* configuration file options */
char *pmo_dbpath = NULL;
PMList *pmo_noupgrade = NULL;
PMList *pmo_ignorepkg = NULL;
+unsigned short pmo_usesyslog = 0;
unsigned short pmo_nopassiveftp = 0;
@@ -89,6 +92,7 @@ PMList *pm_targets = NULL;
char *lckfile = "/tmp/pacman.lck";
char *workfile = NULL;
enum {READ_ONLY, READ_WRITE} pm_access;
+int maxcols = 80;
int main(int argc, char *argv[])
{
@@ -96,6 +100,12 @@ int main(int argc, char *argv[])
char *ptr = NULL;
char path[PATH_MAX];
pacdb_t *db_local = NULL;
+ char *cenv = NULL;
+
+ cenv = getenv("COLUMNS");
+ if(cenv) {
+ maxcols = atoi(cenv);
+ }
/* default root */
MALLOC(pmo_root, PATH_MAX);
@@ -118,7 +128,7 @@ int main(int argc, char *argv[])
/* check for permission */
pm_access = READ_ONLY;
if(pmo_op != PM_MAIN && pmo_op != PM_QUERY && pmo_op != PM_DEPTEST) {
- if(pmo_op == PM_SYNC && pmo_s_search) {
+ if(pmo_op == PM_SYNC && !pmo_s_sync && (pmo_s_search || pmo_group)) {
/* special case: PM_SYNC can be used w/ pmo_s_search by any user */
} else {
if(geteuid() != 0) {
@@ -136,11 +146,6 @@ int main(int argc, char *argv[])
}
}
- vprint("Installation Root: %s\n", pmo_root);
- if(pmo_verbose) {
- list_display("Targets: ", pm_targets);
- }
-
/* set signal handlers */
signal(SIGINT, cleanup);
signal(SIGTERM, cleanup);
@@ -151,6 +156,10 @@ int main(int argc, char *argv[])
cleanup(1);
}
+ if(pmo_usesyslog) {
+ openlog("pacman", 0, LOG_USER);
+ }
+
/* check for db existence */
/* add a trailing '/' if there isn't one */
if(pmo_root[strlen(pmo_root)-1] != '/') {
@@ -160,8 +169,13 @@ int main(int argc, char *argv[])
FREE(pmo_root);
pmo_root = ptr;
}
+
+ vprint("Installation Root: %s\n", pmo_root);
/* db location */
vprint("Top-level DB Path: %s%s\n", pmo_root, pmo_dbpath);
+ if(pmo_verbose) {
+ list_display("Targets: ", pm_targets);
+ }
db_local = db_open(pmo_root, pmo_dbpath, "local");
if(db_local == NULL) {
@@ -281,10 +295,10 @@ int pacman_deptest(pacdb_t *db, PMList *targets)
int pacman_sync(pacdb_t *db, PMList *targets)
{
int allgood = 1, confirm = 0;
- int cols;
PMList *i, *j, *k;
- PMList *final = NULL;
- PMList *trail = NULL;
+ PMList *rmtargs = NULL; /* conflicting packages to remove */
+ PMList *final = NULL; /* packages to upgrade */
+ PMList *trail = NULL; /* a breadcrumb trail to avoid running in circles */
PMList *databases = NULL;
if(!list_count(pmc_syncs)) {
@@ -302,7 +316,7 @@ int pacman_sync(pacdb_t *db, PMList *targets)
}
oldmask = umask(0000);
- if(makepath("/var/cache/pacman/pkg")) {
+ if(makepath("/var/cache/pacman/pkg")) {
fprintf(stderr, "error: could not create new cache directory: %s\n", strerror(errno));
return(1);
}
@@ -312,9 +326,12 @@ int pacman_sync(pacdb_t *db, PMList *targets)
return(0);
}
- if(pmo_s_sync && !pmo_s_search) {
+ if(pmo_s_sync) {
/* grab a fresh package list */
printf(":: Synchronizing package databases... \n");
+ if(pmo_usesyslog) {
+ syslog(LOG_INFO, "synchronizing package lists");
+ }
sync_synctree();
}
@@ -324,7 +341,7 @@ int pacman_sync(pacdb_t *db, PMList *targets)
dbsync_t *dbs = NULL;
sync_t *sync = (sync_t*)i->data;
- db_sync = db_open(pmo_root, PKGDIR, sync->treename);
+ db_sync = db_open(pmo_root, pmo_dbpath, sync->treename);
if(db_sync == NULL) {
fprintf(stderr, "error: could not open sync database: %s\n", sync->treename);
fprintf(stderr, " have you used --refresh yet?\n");
@@ -344,45 +361,157 @@ int pacman_sync(pacdb_t *db, PMList *targets)
if(pmo_s_search) {
/* search sync databases */
- for(i = targets; i; i = i->next) {
- char *targ = strdup(i->data);
- strtoupper(targ);
- for(j = databases; j; j = j->next) {
- dbsync_t *dbs = (dbsync_t*)j->data;
- for(k = dbs->pkgcache; k; k = k->next) {
- pkginfo_t *pkg = (pkginfo_t*)k->data;
- char *haystack;
- /* check name */
- haystack = strdup(pkg->name);
- strtoupper(haystack);
- if(strstr(haystack, targ)) {
- printf("%s/%s %s\n ", dbs->sync->treename, pkg->name, pkg->version);
- indentprint(pkg->desc, 4);
- printf("\n");
- } else {
- /* check description */
- FREE(haystack);
- haystack = strdup(pkg->desc);
+ if(targets) {
+ for(i = targets; i; i = i->next) {
+ char *targ = strdup(i->data);
+ strtoupper(targ);
+ for(j = databases; j; j = j->next) {
+ dbsync_t *dbs = (dbsync_t*)j->data;
+ for(k = dbs->pkgcache; k; k = k->next) {
+ pkginfo_t *pkg = (pkginfo_t*)k->data;
+ char *haystack;
+ /* check name */
+ haystack = strdup(pkg->name);
strtoupper(haystack);
if(strstr(haystack, targ)) {
printf("%s/%s %s\n ", dbs->sync->treename, pkg->name, pkg->version);
indentprint(pkg->desc, 4);
printf("\n");
+ } else {
+ /* check description */
+ FREE(haystack);
+ haystack = strdup(pkg->desc);
+ strtoupper(haystack);
+ if(strstr(haystack, targ)) {
+ printf("%s/%s %s\n ", dbs->sync->treename, pkg->name, pkg->version);
+ indentprint(pkg->desc, 4);
+ printf("\n");
+ }
}
+ FREE(haystack);
+ }
+ }
+ FREE(targ);
+ }
+ } else {
+ for(j = databases; j; j = j->next) {
+ dbsync_t *dbs = (dbsync_t*)j->data;
+ for(k = dbs->pkgcache; k; k = k->next) {
+ pkginfo_t *pkg = (pkginfo_t*)k->data;
+ printf("%s/%s %s\n ", dbs->sync->treename, pkg->name, pkg->version);
+ indentprint(pkg->desc, 4);
+ printf("\n");
+ }
+ }
+ }
+ } else if(pmo_group) {
+ PMList *pm, *allgroups, *groups;
+ i = NULL;
+ /* fetch the list of existing groups */
+ for(j = databases; j; j = j->next) {
+ dbsync_t *dbs = (dbsync_t*)j->data;
+ k = find_groups(dbs->db);
+ for(pm = k; pm; pm = pm->next) {
+ if(!is_in((char *)pm->data, i)) {
+ i = list_add(i, strdup((char *)pm->data));
+ }
+ }
+ list_free(k);
+ }
+ allgroups = list_sort(i);
+ list_free(i);
+ if(targets) {
+ groups = NULL;
+ for(j = targets; j; j = j->next) {
+ if(is_in((char *)j->data, allgroups)) {
+ groups = list_add(groups, (char *)j->data);
+ }
+ }
+ list_free(allgroups);
+ } else {
+ groups = allgroups;
+ }
+ /* display the packages belonging to groups */
+ for(pm = groups; pm; pm = pm->next) {
+ PMList *pkg;
+ printf("%s\n", (char *)pm->data);
+ i = NULL;
+ for(j = databases; j; j = j->next) {
+ PMList *lp;
+ dbsync_t *dbs = (dbsync_t*)j->data;
+ k = pkg_ingroup(dbs->db, (char *)pm->data);
+ for(lp = k; lp; lp = lp->next) {
+ if(!is_in((char *)lp->data, i)) {
+ i = list_add(i, strdup((char *)lp->data));
}
- FREE(haystack);
}
+ list_free(k);
}
- FREE(targ);
+ pkg = list_sort(i);
+ list_free(i);
+ list_display(" ", pkg);
+ list_free(pkg);
}
+ list_free(groups);
} else if(pmo_s_upgrade) {
int newer = 0;
int ignore = 0;
+ if(pmo_usesyslog) {
+ syslog(LOG_INFO, "starting full system upgrade");
+ }
+ /* check for "recommended" package replacements */
+ for(i = databases; i && allgood; i = i->next) {
+ dbsync_t *dbs = (dbsync_t*)i->data;
+ for(j = dbs->pkgcache; j; j = j->next) {
+ pkginfo_t *pkg = (pkginfo_t*)j->data;
+ for(k = pkg->replaces; k; k = k->next) {
+ PMList *m;
+ for(m = pm_packages; m; m = m->next) {
+ pkginfo_t *p = (pkginfo_t*)m->data;
+ if(!strcmp(k->data, p->name)) {
+ /* if confirmed, add this to the 'final' list, designating 'p' as
+ * the package to replace.
+ */
+ if(yesno(":: replace %s with %s from \"%s\"? [Y/n] ", p->name, pkg->name, dbs->db->treename)) {
+ syncpkg_t *sync = NULL;
+ /* we save the dependency info so we can move p's requiredby stuff
+ * over to the replacing package
+ */
+ pkginfo_t *q = db_scan(db, p->name, INFRQ_DESC | INFRQ_DEPENDS);
+
+ /* check if pkg->name is already in the final list. */
+ sync = find_pkginsync(pkg->name, final);
+ if(sync) {
+ /* found it -- just append to the replaces list */
+ sync->replaces = list_add(sync->replaces, q);
+ } else {
+ /* none found -- enter pkg into the final sync list */
+ MALLOC(sync, sizeof(syncpkg_t));
+ sync->dbs = dbs;
+ sync->replaces = NULL;
+ sync->replaces = list_add(sync->replaces, q);
+ sync->pkg = db_scan(sync->dbs->db, pkg->name, INFRQ_DESC | INFRQ_DEPENDS);
+ /* add to the targets list */
+ allgood = !resolvedeps(db, databases, sync, final, trail);
+ /* check again, as resolvedeps could have added our target for us */
+ if(find_pkginsync(sync->pkg->name, final) == NULL) {
+ final = list_add(final, sync);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ /* match installed packages with the sync dbs and compare versions */
for(i = pm_packages; i && allgood; i = i->next) {
int cmp, found = 0;
pkginfo_t *local = (pkginfo_t*)i->data;
syncpkg_t *sync = NULL;
MALLOC(sync, sizeof(syncpkg_t));
+ sync->replaces = NULL;
for(j = databases; !found && j; j = j->next) {
dbsync_t *dbs = (dbsync_t*)j->data;
@@ -426,11 +555,11 @@ int pacman_sync(pacdb_t *db, PMList *targets)
sync->pkg = db_scan(sync->dbs->db, sync->pkg->name, INFRQ_DESC | INFRQ_DEPENDS);
/* add to the targets list */
- found = is_pkginsync(sync, final);
+ found = (find_pkginsync(sync->pkg->name, final) != NULL);
if(!found) {
allgood = !resolvedeps(db, databases, sync, final, trail);
/* check again, as resolvedeps could have added our target for us */
- found = is_pkginsync(sync, final);
+ found = (find_pkginsync(sync->pkg->name, final) != NULL);
if(!found) {
final = list_add(final, sync);
}
@@ -443,17 +572,24 @@ int pacman_sync(pacdb_t *db, PMList *targets)
/* process targets */
for(i = targets; i && allgood; i = i->next) {
if(i->data) {
- int cmp, found = 0;
+ int cmp, found = 0, group = 0;
pkginfo_t *local;
syncpkg_t *sync = NULL;
MALLOC(sync, sizeof(syncpkg_t));
+ sync->replaces = NULL;
local = db_scan(db, (char*)i->data, INFRQ_DESC);
for(j = databases; !found && j; j = j->next) {
dbsync_t *dbs = (dbsync_t*)j->data;
for(k = dbs->pkgcache; !found && k; k = k->next) {
pkginfo_t *pkg = (pkginfo_t*)k->data;
- if(!strcmp((char*)i->data, pkg->name)) {
+ if(is_in((char*)i->data, pkg->groups)) {
+ group = 1;
+ if(!yesno(":: install %s from group %s? [Y/n] ", pkg->name, (char*)i->data)) {
+ continue;
+ }
+ targets = list_add(targets, strdup(pkg->name));
+ } else if(!strcmp((char*)i->data, pkg->name)) {
found = 1;
sync->dbs = dbs;
/* re-fetch the package record with dependency info */
@@ -464,9 +600,11 @@ int pacman_sync(pacdb_t *db, PMList *targets)
}
}
}
- if(!found) {
- fprintf(stderr, "%s: not found in sync db\n", (char*)i->data);
- allgood = 0;
+ if(!found || group) {
+ if(!group) {
+ fprintf(stderr, "%s: not found in sync db\n", (char*)i->data);
+ allgood = 0;
+ }
freepkg(local);
FREE(sync);
continue;
@@ -494,11 +632,11 @@ int pacman_sync(pacdb_t *db, PMList *targets)
}
freepkg(local);
- found = is_pkginsync(sync, final);
+ found = (find_pkginsync(sync->pkg->name, final) != NULL);
if(!found && !pmo_nodeps) {
allgood = !resolvedeps(db, databases, sync, final, trail);
/* check again, as resolvedeps could have added our target for us */
- found = is_pkginsync(sync, final);
+ found = (find_pkginsync(sync->pkg->name, final) != NULL);
}
if(!found) {
final = list_add(final, sync);
@@ -509,25 +647,26 @@ int pacman_sync(pacdb_t *db, PMList *targets)
if(allgood) {
/* check for inter-conflicts and whatnot */
- PMList *deps = NULL;
- PMList *list = NULL;
+ if(!pmo_nodeps && !pmo_s_downloadonly) {
+ int errorout = 0;
+ PMList *deps = NULL;
+ PMList *list = NULL;
- for(i = final; i; i = i->next) {
- syncpkg_t *s = (syncpkg_t*)i->data;
- if(s) {
- list = list_add(list, s->pkg);
+ for(i = final; i; i = i->next) {
+ syncpkg_t *s = (syncpkg_t*)i->data;
+ if(s) {
+ list = list_add(list, s->pkg);
+ }
}
- }
-
- if(!pmo_nodeps && !pmo_s_upgrade) {
deps = checkdeps(db, PM_UPGRADE, list);
if(deps) {
- fprintf(stderr, "error: unresolvable conflicts/dependencies:\n");
for(i = deps; i; i = i->next) {
depmissing_t *miss = (depmissing_t*)i->data;
- if(miss->type == CONFLICT) {
- fprintf(stderr, " %s: conflicts with %s\n", miss->target, miss->depend.name);
- } else if(miss->type == DEPEND || miss->type == REQUIRED) {
+ if(miss->type == DEPEND || miss->type == REQUIRED) {
+ if(!errorout) {
+ fprintf(stderr, "error: unresolvable dependencies:\n");
+ errorout = 1;
+ }
fprintf(stderr, " %s: requires %s", miss->target, miss->depend.name);
switch(miss->depend.mod) {
case DEP_EQ: fprintf(stderr, "=%s", miss->depend.version); break;
@@ -540,55 +679,137 @@ int pacman_sync(pacdb_t *db, PMList *targets)
fprintf(stderr, "\n");
}
}
- FREE(miss);
- i->data = NULL;
+ }
+ if(!errorout) {
+ int found;
+ errorout = 0;
+ /* no unresolvable deps, so look for conflicts */
+ for(i = deps; i && !errorout; i = i->next) {
+ depmissing_t *miss = (depmissing_t*)i->data;
+ if(miss->type == CONFLICT) {
+ /* check if the conflicting package is one that's about to be removed/replaced.
+ * if so, then just ignore it
+ */
+ found = 0;
+ for(j = final; j && !found; j = j->next) {
+ syncpkg_t *sync = (syncpkg_t*)j->data;
+ for(k = sync->replaces; k && !found; k = k->next) {
+ pkginfo_t *p = (pkginfo_t*)k->data;
+ if(!strcmp(p->name, miss->depend.name)) {
+ found = 1;
+ }
+ }
+ }
+ /* if we didn't find it in any sync->replaces lists, then it's a conflict */
+ if(!found && !is_in(miss->depend.name, rmtargs)) {
+ pkginfo_t p1;
+ /* build a "fake" pkginfo_t so we can search with is_pkgin() */
+ snprintf(p1.name, sizeof(p1.name), miss->depend.name);
+ sprintf(p1.version, "1.0-1");
+
+ if(is_pkgin(&p1, pm_packages)) {
+ if(yesno(":: %s conflicts with %s. Remove %s? [Y/n] ",
+ miss->target, miss->depend.name, miss->depend.name)) {
+ /* remove miss->depend.name */
+ rmtargs = list_add(rmtargs, strdup(miss->depend.name));
+ } else {
+ /* abort */
+ fprintf(stderr, "\nerror: package conflicts detected\n");
+ errorout = 1;
+ }
+ } else {
+ if(!is_in(miss->depend.name, rmtargs) & !is_in(miss->target, rmtargs)) {
+ fprintf(stderr, "\nerror: %s conflicts with %s\n", miss->target,
+ miss->depend.name);
+ errorout = 1;
+ }
+ }
+ }
+ }
+ }
}
list_free(deps);
- /* abort mission */
- allgood = 0;
+ if(errorout) {
+ /* abort mission */
+ allgood = 0;
+ }
+ }
+ /* cleanup */
+ for(i = list; i; i = i->next) {
+ i->data = NULL;
}
+ list_free(list);
+ list = NULL;
}
- /* cleanup */
- for(i = list; i; i = i->next) {
+ /* any packages in rmtargs need to be removed from final. */
+ /* rather than ripping out nodes from final, we just copy over */
+ /* our "good" nodes to a new list and reassign. */
+ k = NULL;
+ for(i = final; i; i = i->next) {
+ syncpkg_t *s = (syncpkg_t*)i->data;
+ int keepit = 1;
+ for(j = rmtargs; j && keepit; j = j->next) {
+ if(!strcmp(j->data, s->pkg->name)) {
+ FREE(i->data);
+ keepit = 0;
+ }
+ }
+ if(keepit) {
+ k = list_add(k, s);
+ }
i->data = NULL;
}
- list_free(list);
- list = NULL;
+ list_free(final);
+ final = k;
/* list targets */
- if(final && final->data) {
- fprintf(stderr, "\nTargets: ");
- }
- cols = 9;
- for(i = final; allgood && i; i = i->next) {
- syncpkg_t *s = (syncpkg_t*)i->data;
- if(s && s->pkg) {
- char t[PATH_MAX];
- int len;
- snprintf(t, PATH_MAX, "%s-%s ", s->pkg->name, s->pkg->version);
- len = strlen(t);
- if(len+cols > 78) {
- cols = 9;
- fprintf(stderr, "\n%9s", " ");
+ if(final && final->data && allgood) {
+ PMList *list = NULL;
+ for(i = rmtargs; i; i = i->next) {
+ list = list_add(list, strdup(i->data));
+ }
+ for(i = final; i; i = i->next) {
+ syncpkg_t *s = (syncpkg_t*)i->data;
+ for(j = s->replaces; j; j = j->next) {
+ pkginfo_t *p = (pkginfo_t*)j->data;
+ list = list_add(list, strdup(p->name));
+ }
+ }
+ if(list) {
+ printf("\nRemove: ");
+ indentprint(buildstring(list), 9);
+ printf("\n");
+ list_free(list);
+ list = NULL;
+ }
+ for(i = final; i; i = i->next) {
+ syncpkg_t *s = (syncpkg_t*)i->data;
+ if(s && s->pkg) {
+ char *str = NULL;
+ MALLOC(str, strlen(s->pkg->name)+strlen(s->pkg->version)+2);
+ sprintf(str, "%s-%s", s->pkg->name, s->pkg->version);
+ list = list_add(list, str);
}
- fprintf(stderr, "%s", t);
- cols += len;
}
+ printf("\nTargets: ");
+ indentprint(buildstring(list), 9);
+ printf("\n");
+ list_free(list);
+ list = NULL;
}
- printf("\n");
/* get confirmation */
confirm = 0;
if(allgood && final && final->data) {
if(pmo_s_downloadonly) {
- confirm = yesno("\nDo you want to download these packages? [Y/n] ");
+ confirm = yesno("\nProceed with download? [Y/n] ");
} else {
/* don't get any confirmation if we're called from makepkg */
if(pmo_d_resolve) {
confirm = 1;
} else {
- confirm = yesno("\nDo you want to install/upgrade these packages? [Y/n] ");
+ confirm = yesno("\nProceed with upgrade? [Y/n] ");
}
}
}
@@ -646,21 +867,21 @@ int pacman_sync(pacdb_t *db, PMList *targets)
/* no cache directory.... try creating it */
snprintf(parent, PATH_MAX, "%svar/cache/pacman", pmo_root);
- fprintf(stderr, "warning: no %s cache exists. creating...\n", ldir);
+ logaction("warning: no %s cache exists. creating...\n", ldir);
oldmask = umask(0000);
mkdir(parent, 0755);
if(mkdir(ldir, 0755)) {
/* couldn't mkdir the cache directory, so fall back to /tmp and unlink
* the package afterwards.
*/
- fprintf(stderr, "warning: couldn't create package cache, using /tmp instead\n");
+ logaction("warning: couldn't create package cache, using /tmp instead\n");
snprintf(ldir, PATH_MAX, "/tmp");
varcache = 0;
}
umask(oldmask);
}
if(downloadfiles(current->servers, ldir, files)) {
- fprintf(stderr, "error: failed to retrieve some files from %s.\n", current->treename);
+ fprintf(stderr, "error: failed to retrieve some files from %s\n", current->treename);
allgood = 0;
}
count += list_count(files);
@@ -680,7 +901,21 @@ int pacman_sync(pacdb_t *db, PMList *targets)
}
if(!pmo_s_downloadonly) {
- /* install targets */
+ /* remove any conflicting packages (WITH dep checks) */
+ if(rmtargs) {
+ int retcode;
+ retcode = pacman_remove(db, rmtargs);
+ list_free(rmtargs);
+ rmtargs = NULL;
+ if(retcode == 1) {
+ fprintf(stderr, "\nupgrade aborted.\n");
+ allgood = 0;
+ }
+ /* reload package cache */
+ pm_packages = db_loadpkgs(db, pm_packages);
+ }
+ list_free(rmtargs);
+ rmtargs = NULL;
for(i = final; allgood && i; i = i->next) {
char *str;
syncpkg_t *sync = (syncpkg_t*)i->data;
@@ -689,10 +924,58 @@ int pacman_sync(pacdb_t *db, PMList *targets)
snprintf(str, PATH_MAX, "%s/%s-%s.pkg.tar.gz", ldir, sync->pkg->name, sync->pkg->version);
files = list_add(files, str);
}
+ for(j = sync->replaces; j; j = j->next) {
+ pkginfo_t *pkg = (pkginfo_t*)j->data;
+ rmtargs = list_add(rmtargs, pkg->name);
+ }
+ }
+ /* remove to-be-replaced packages */
+ if(allgood && rmtargs) {
+ int oldval = pmo_nodeps;
+ /* we make pacman_remove() skip dependency checks by setting pmo_nodeps high */
+ pmo_nodeps = 1;
+ allgood = !pacman_remove(db, rmtargs);
+ pmo_nodeps = oldval;
+ if(!allgood) {
+ fprintf(stderr, "package removal failed. aborting...\n");
+ }
}
+ /* install targets */
if(allgood) {
allgood = !pacman_upgrade(db, files);
}
+ /* propagate replaced packages' requiredby fields to their new owners */
+ if(allgood) {
+ for(i = final; i; i = i->next) {
+ syncpkg_t *sync = (syncpkg_t*)i->data;
+ if(sync->replaces) {
+ pkginfo_t *new = db_scan(db, sync->pkg->name, INFRQ_ALL);
+ for(j = sync->replaces; j; j = j->next) {
+ pkginfo_t *old = (pkginfo_t*)j->data;
+ /* merge lists */
+ for(k = old->requiredby; k; k = k->next) {
+ if(!is_in(k->data, new->requiredby)) {
+ /* replace old's name with new's name in the requiredby's dependency list */
+ PMList *m;
+ pkginfo_t *depender = db_scan(db, k->data, INFRQ_ALL);
+ for(m = depender->depends; m; m = m->next) {
+ if(!strcmp(m->data, old->name)) {
+ FREE(m->data);
+ m->data = strdup(new->name);
+ }
+ }
+ db_write(db, depender);
+
+ /* add the new requiredby */
+ new->requiredby = list_add(new->requiredby, k->data);
+ }
+ }
+ }
+ db_write(db, new);
+ freepkg(new);
+ }
+ }
+ }
}
if(!varcache && !pmo_s_downloadonly) {
@@ -706,7 +989,14 @@ int pacman_sync(pacdb_t *db, PMList *targets)
/* cleanup */
for(i = final; i; i = i->next) {
syncpkg_t *sync = (syncpkg_t*)i->data;
- if(sync) freepkg(sync->pkg);
+ if(sync) {
+ freepkg(sync->pkg);
+ for(j = sync->replaces; j; j = j->next) {
+ freepkg(j->data);
+ j->data = NULL;
+ }
+ list_free(sync->replaces);
+ }
FREE(sync);
i->data = NULL;
}
@@ -717,6 +1007,14 @@ int pacman_sync(pacdb_t *db, PMList *targets)
for(i = databases; i; i = i->next) {
dbsync_t *dbs = (dbsync_t*)i->data;
db_close(dbs->db);
+ for(j = dbs->pkgcache; j; j = j->next) {
+ if(j->data) {
+ /* XXX: this freepkg() still locks up, but only when the "replaces"
+ * code has been run
+ freepkg(j->data);*/
+ j->data = NULL;
+ }
+ }
list_free(dbs->pkgcache);
FREE(dbs);
i->data = NULL;
@@ -724,6 +1022,7 @@ int pacman_sync(pacdb_t *db, PMList *targets)
list_free(databases);
list_free(final);
list_free(trail);
+ list_free(rmtargs);
return(!allgood);
}
@@ -735,7 +1034,7 @@ int pacman_add(pacdb_t *db, PMList *targets)
char pm_install[PATH_MAX];
pkginfo_t *info = NULL;
struct stat buf;
- PMList *targ, *file, *lp, *j;
+ PMList *targ, *file, *lp, *j, *k;
PMList *alltargs = NULL;
PMList *filenames = NULL;
unsigned short real_pmo_upgrade;
@@ -777,33 +1076,115 @@ int pacman_add(pacdb_t *db, PMList *targets)
/* No need to check deps if pacman_add was called during a sync:
* it is already done in pacman_sync. */
if(!pmo_nodeps && pmo_op != PM_SYNC) {
+ int errorout = 0;
vprint("checking dependencies...\n");
lp = checkdeps(db, (pmo_upgrade ? PM_UPGRADE : PM_ADD), alltargs);
if(lp) {
- fprintf(stderr, "error: unsatisfied dependencies:\n");
+ /* look for unsatisfied dependencies */
for(j = lp; j; j = j->next) {
depmissing_t* miss = (depmissing_t*)j->data;
- printf(" %s: ", miss->target);
if(miss->type == DEPEND || miss->type == REQUIRED) {
- printf("requires %s", miss->depend.name);
+ if(!errorout) {
+ fprintf(stderr, "error: unsatisfied dependencies:\n");
+ errorout = 1;
+ }
+ printf(" %s: requires %s", miss->target, miss->depend.name);
switch(miss->depend.mod) {
case DEP_EQ: printf("=%s", miss->depend.version); break;
case DEP_GE: printf(">=%s", miss->depend.version); break;
case DEP_LE: printf("<=%s", miss->depend.version); break;
}
printf("\n");
- } else if(miss->type == CONFLICT) {
- printf("conflicts with %s\n", miss->depend.name);
}
}
+ if(!errorout) {
+ PMList *rmtargs = NULL;
+ errorout = 0;
+ /* no unsatisfied deps, so look for conflicts */
+ for(j = lp; j && !errorout; j = j->next) {
+ depmissing_t* miss = (depmissing_t*)j->data;
+ if(miss->type == CONFLICT && !is_in(miss->depend.name, rmtargs)) {
+ pkginfo_t p1;
+ /* build a "fake" pkginfo_t so we can search with is_pkgin() */
+ snprintf(p1.name, sizeof(p1.name), miss->depend.name);
+ sprintf(p1.version, "1.0-1");
+
+ if(is_pkgin(&p1, pm_packages)) {
+ if(yesno(":: %s conflicts with %s. Remove %s? [Y/n] ",
+ miss->target, miss->depend.name, miss->depend.name)) {
+ /* remove miss->depend.name */
+ rmtargs = list_add(rmtargs, strdup(miss->depend.name));
+ } else {
+ /* abort */
+ fprintf(stderr, "\nerror: package conflicts detected\n");
+ errorout = 1;
+ }
+ } else {
+ if(!is_in(miss->depend.name, rmtargs) & !is_in(miss->target, rmtargs)) {
+ fprintf(stderr, "\nerror: %s conflicts with %s\n", miss->target,
+ miss->depend.name);
+ errorout = 1;
+ }
+ }
+ }
+ }
+ if(rmtargs && !errorout) {
+ int retcode;
+ int oldupg = pmo_upgrade;
+ /* any packages in rmtargs need to be removed from alltargs. */
+ /* rather than ripping out nodes from alltargs, we just copy over */
+ /* our "good" nodes to a new list and reassign. */
+ k = NULL;
+ for(lp = alltargs; lp; lp = lp->next) {
+ pkginfo_t *p = (pkginfo_t*)lp->data;
+ int keepit = 1;
+ for(j = rmtargs; j && keepit; j = j->next) {
+ if(!strcmp(j->data, p->name)) {
+ /* gone! */
+ FREE(lp->data);
+ keepit = 0;
+ }
+ }
+ if(keepit) {
+ k = list_add(k, p);
+ }
+ lp->data = NULL;
+ }
+ list_free(alltargs);
+ alltargs = k;
+ /* make sure pacman_remove does it's own dependency check */
+ pmo_upgrade = 0;
+ retcode = pacman_remove(db, rmtargs);
+ list_free(rmtargs);
+ if(retcode == 1) {
+ fprintf(stderr, "\n%s aborted.\n", oldupg ? "upgrade" : "install");
+ return(1);
+ }
+ /* reload package cache */
+ pm_packages = db_loadpkgs(db, pm_packages);
+ pmo_upgrade = oldupg;
+ }
+ }
+ if(errorout) {
+ list_free(lp);
+ return(1);
+ }
list_free(lp);
- return(1);
}
- list_free(lp);
+
+ /* re-order w.r.t. dependencies */
+ vprint("sorting by dependencies\n");
+ lp = sortbydeps(alltargs);
+ /* free the old alltargs */
+ for(j = alltargs; j; j = j->next) {
+ j->data = NULL;
+ }
+ list_free(alltargs);
+ alltargs = lp;
}
if(!pmo_force) {
- printf("checking for conflicts... ");
+ printf("checking for file conflicts... ");
fflush(stdout);
lp = db_find_conflicts(db, alltargs, pmo_root);
if(lp) {
@@ -848,12 +1229,12 @@ int pacman_add(pacdb_t *db, PMList *targets)
vprint("removing old package first...\n");
retcode = pacman_remove(db, tmp);
list_free(tmp);
- /* reload package cache */
- pm_packages = db_loadpkgs(db, pm_packages);
if(retcode == 1) {
fprintf(stderr, "\nupgrade aborted.\n");
return(1);
}
+ /* reload package cache */
+ pm_packages = db_loadpkgs(db, pm_packages);
} else {
/* no previous package version is installed, so this is actually just an
* install
@@ -887,7 +1268,7 @@ int pacman_add(pacdb_t *db, PMList *targets)
if(!strcmp(pathname, "._install") || !strcmp(pathname, ".INSTALL")) {
/* the install script goes inside the db */
snprintf(expath, PATH_MAX, "%s%s/%s/%s-%s/install", pmo_root,
- PKGDIR, db->treename, info->name, info->version);
+ pmo_dbpath, db->treename, info->name, info->version);
} else {
/* build the new pathname relative to pmo_root */
snprintf(expath, PATH_MAX, "%s%s", pmo_root, pathname);
@@ -919,7 +1300,7 @@ int pacman_add(pacdb_t *db, PMList *targets)
temp = strdup("/tmp/pacman_XXXXXX");
mkstemp(temp);
if(tar_extract_file(tar, temp)) {
- fprintf(stderr, "could not extract %s: %s\n", pathname, strerror(errno));
+ logaction("could not extract %s: %s\n", pathname, strerror(errno));
errors++;
continue;
}
@@ -956,13 +1337,13 @@ int pacman_add(pacdb_t *db, PMList *targets)
char newpath[PATH_MAX];
snprintf(newpath, PATH_MAX, "%s.pacorig", expath);
if(rename(expath, newpath)) {
- fprintf(stderr, "error: could not rename %s: %s\n", expath, strerror(errno));
+ logaction("error: could not rename %s: %s\n", expath, strerror(errno));
}
if(copyfile(temp, expath)) {
- fprintf(stderr, "error: could not copy %s to %s: %s\n", temp, expath, strerror(errno));
+ logaction("error: could not copy %s to %s: %s\n", temp, expath, strerror(errno));
errors++;
} else {
- fprintf(stderr, "warning: %s saved as %s\n", expath, newpath);
+ logaction("warning: %s saved as %s\n", expath, newpath);
}
}
} else if(md5_orig) {
@@ -989,9 +1370,9 @@ int pacman_add(pacdb_t *db, PMList *targets)
installnew = 1;
snprintf(newpath, PATH_MAX, "%s.pacsave", expath);
if(rename(expath, newpath)) {
- fprintf(stderr, "error: could not rename %s: %s\n", expath, strerror(errno));
+ logaction("error: could not rename %s: %s\n", expath, strerror(errno));
} else {
- fprintf(stderr, "warning: %s saved as %s\n", expath, newpath);
+ logaction("warning: %s saved as %s\n", expath, newpath);
}
}
@@ -1015,11 +1396,11 @@ int pacman_add(pacdb_t *db, PMList *targets)
} else {
vprint("%s is in NoUpgrade - skipping\n", pathname);
strncat(expath, ".pacnew", PATH_MAX);
- fprintf(stderr, "warning: extracting %s%s as %s\n", pmo_root, pathname, expath);
+ logaction("warning: extracting %s%s as %s\n", pmo_root, pathname, expath);
/*tar_skip_regfile(tar);*/
}
if(tar_extract_file(tar, expath)) {
- fprintf(stderr, "could not extract %s: %s\n", pathname, strerror(errno));
+ logaction("could not extract %s: %s\n", pathname, strerror(errno));
errors++;
}
/* calculate an md5 hash if this is in info->backup */
@@ -1043,7 +1424,7 @@ int pacman_add(pacdb_t *db, PMList *targets)
tar_close(tar);
if(errors) {
ret = 1;
- fprintf(stderr, "errors occurred while %s %s\n",
+ logaction("errors occurred while %s %s\n",
(pmo_upgrade ? "upgrading" : "installing"), info->name);
/* XXX: this "else" is disabled so the db_write() ALWAYS occurs. If it doesn't
@@ -1059,7 +1440,7 @@ int pacman_add(pacdb_t *db, PMList *targets)
PMList *tmppm = NULL;
tmpp = db_scan(db, ((pkginfo_t*)lp->data)->name, INFRQ_DEPENDS);
- if (tmpp == NULL) {
+ if(tmpp == NULL) {
continue;
}
for(tmppm = tmpp->depends; tmppm; tmppm = tmppm->next) {
@@ -1078,10 +1459,18 @@ int pacman_add(pacdb_t *db, PMList *targets)
/* make an install date (in UTC) */
strncpy(info->installdate, asctime(gmtime(&t)), sizeof(info->installdate));
if(db_write(db, info)) {
- fprintf(stderr, "error updating database for %s!\n", info->name);
+ logaction("error updating database for %s!\n", info->name);
return(1);
}
vprint("done.\n");
+ if(pmo_usesyslog) {
+ if(pmo_upgrade) {
+ syslog(LOG_INFO, "upgraded %s (%s -> %s)\n", info->name,
+ oldpkg->version, info->version);
+ } else {
+ syslog(LOG_INFO, "installed %s (%s)\n", info->name, info->version);
+ }
+ }
/* update dependency packages' REQUIREDBY fields */
for(lp = info->depends; lp; lp = lp->next) {
@@ -1093,7 +1482,18 @@ int pacman_add(pacdb_t *db, PMList *targets)
}
depinfo = db_scan(db, depend.name, INFRQ_ALL);
if(depinfo == NULL) {
- continue;
+ /* look for a provides package */
+ PMList *provides = whatprovides(db, depend.name);
+ if(provides) {
+ /* use the first one */
+ depinfo = db_scan(db, provides->data, INFRQ_ALL);
+ if(depinfo == NULL) {
+ /* wtf */
+ continue;
+ }
+ } else {
+ continue;
+ }
}
depinfo->requiredby = list_add(depinfo->requiredby, strdup(info->name));
db_write(db, depinfo);
@@ -1102,10 +1502,10 @@ int pacman_add(pacdb_t *db, PMList *targets)
printf("done.\n"); fflush(stdout);
/* run the post-install script if it exists */
- snprintf(pm_install, PATH_MAX, "%s%s/%s/%s-%s/install", pmo_root, PKGDIR, db->treename, info->name, info->version);
+ snprintf(pm_install, PATH_MAX, "%s%s/%s/%s-%s/install", pmo_root, pmo_dbpath, db->treename, info->name, info->version);
if(!stat(pm_install, &buf)) {
char cmdline[PATH_MAX+1];
- snprintf(pm_install, PATH_MAX, "%s/%s/%s-%s/install", PKGDIR, db->treename, info->name, info->version);
+ snprintf(pm_install, PATH_MAX, "%s/%s/%s-%s/install", pmo_dbpath, db->treename, info->name, info->version);
vprint("Executing post-install script...\n");
snprintf(cmdline, PATH_MAX, "chroot %s /bin/sh %s post_%s %s %s", pmo_root, pm_install,
(pmo_upgrade ? "upgrade" : "install"), info->version, (pmo_upgrade ? oldpkg->version : ""));
@@ -1159,43 +1559,46 @@ int pacman_remove(pacdb_t *db, PMList *targets)
for(lp = targets; lp; lp = lp->next) {
info = db_scan(db, (char*)lp->data, INFRQ_ALL);
if(info == NULL) {
+ PMList *groups;
+ /* if the target is a group, ask if its packages should be removed */
+ groups = find_groups(db);
+ if(is_in((char *)lp->data, groups)) {
+ PMList *pkg;
+ pkg = pkg_ingroup(db, (char *)lp->data);
+ for(j = pkg; j; j = j->next) {
+ if(yesno(":: Remove %s from group %s? [Y/n] ", (char *)j->data, (char *)lp->data)) {
+ info = db_scan(db, (char *)j->data, INFRQ_ALL);
+ alltargs = list_add(alltargs, info);
+ }
+ }
+ list_free(pkg);
+ list_free(groups);
+ continue;
+ }
+ list_free(groups);
fprintf(stderr, "error: could not find %s in database\n", (char*)lp->data);
return(1);
}
alltargs = list_add(alltargs, info);
}
if(!pmo_nodeps && !pmo_upgrade) {
- vprint("Checking dependencies...\n");
+ vprint("checking dependencies...\n");
lp = checkdeps(db, PM_REMOVE, alltargs);
if(lp) {
if(pmo_r_cascade) {
- int cols;
while(lp) {
for(j = lp; j; j = j->next) {
depmissing_t* miss = (depmissing_t*)j->data;
- miss = (depmissing_t*)j->data;
info = db_scan(db, miss->depend.name, INFRQ_ALL);
- list_add(alltargs, info);
+ if(!is_pkgin(info, alltargs)) {
+ list_add(alltargs, info);
+ }
}
list_free(lp);
lp = checkdeps(db, PM_REMOVE, alltargs);
}
/* list targets */
- fprintf(stderr, "\nTargets: ");
- cols = 9;
- for(j = alltargs; j; j = j->next) {
- char t[PATH_MAX];
- int len;
- snprintf(t, PATH_MAX, "%s ", (char*)j->data);
- len = strlen(t);
- if(len+cols > 78) {
- cols = 9;
- fprintf(stderr, "\n%9s", " ");
- }
- fprintf(stderr, "%s", t);
- cols += len;
- }
- printf("\n");
+ list_display("\nTargets: ", alltargs);
/* get confirmation */
if(yesno("\nDo you want to remove these packages? [Y/n] ") == 0) {
list_free(alltargs);
@@ -1223,10 +1626,10 @@ int pacman_remove(pacdb_t *db, PMList *targets)
printf("removing %s... ", info->name);
fflush(stdout);
/* run the pre-remove script if it exists */
- snprintf(pm_install, PATH_MAX, "%s%s/%s/%s-%s/install", pmo_root, PKGDIR, db->treename, info->name, info->version);
+ snprintf(pm_install, PATH_MAX, "%s%s/%s/%s-%s/install", pmo_root, pmo_dbpath, db->treename, info->name, info->version);
if(!stat(pm_install, &buf)) {
vprint("Executing pre-remove script...\n");
- snprintf(pm_install, PATH_MAX, "%s/%s/%s-%s/install", PKGDIR, db->treename, info->name, info->version);
+ snprintf(pm_install, PATH_MAX, "%s/%s/%s-%s/install", pmo_dbpath, db->treename, info->name, info->version);
snprintf(line, PATH_MAX, "chroot %s /bin/sh %s pre_remove %s", pmo_root, pm_install, info->version);
system(line);
@@ -1265,7 +1668,7 @@ int pacman_remove(pacdb_t *db, PMList *targets)
newpath = (char*)realloc(newpath, strlen(line)+strlen(".pacsave")+1);
sprintf(newpath, "%s.pacsave", line);
rename(line, newpath);
- fprintf(stderr, "warning: %s saved as %s\n", line, newpath);
+ logaction("warning: %s saved as %s\n", line, newpath);
} else {
/*vprint(" unlinking %s\n", line);*/
if(unlink(line)) {
@@ -1283,7 +1686,7 @@ int pacman_remove(pacdb_t *db, PMList *targets)
}
/* remove the package from the database */
- snprintf(line, PATH_MAX, "%s%s/%s/%s-%s", pmo_root, PKGDIR, db->treename,
+ snprintf(line, PATH_MAX, "%s%s/%s/%s-%s", pmo_root, pmo_dbpath, db->treename,
info->name, info->version);
/* DESC */
@@ -1310,7 +1713,20 @@ int pacman_remove(pacdb_t *db, PMList *targets)
}
depinfo = db_scan(db, depend.name, INFRQ_ALL);
if(depinfo == NULL) {
- continue;
+ /* look for a provides package */
+ PMList *provides = whatprovides(db, depend.name);
+ if(provides) {
+ /* use the first one */
+ depinfo = db_scan(db, provides->data, INFRQ_ALL);
+ list_free(provides);
+ if(depinfo == NULL) {
+ /* wtf */
+ continue;
+ }
+ } else {
+ list_free(provides);
+ continue;
+ }
}
/* splice out this entry from requiredby */
last = list_last(depinfo->requiredby);
@@ -1332,6 +1748,9 @@ int pacman_remove(pacdb_t *db, PMList *targets)
}
if(!pmo_upgrade) {
printf("done.\n");
+ if(pmo_usesyslog) {
+ syslog(LOG_INFO, "removed %s (%s)\n", info->name, info->version);
+ }
}
}
@@ -1369,6 +1788,34 @@ int pacman_query(pacdb_t *db, PMList *targets)
}
package = (char*)targ->data;
}
+
+ /* looking for groups */
+ if(pmo_group) {
+ PMList *pkg, *groups;
+ groups = find_groups(db);
+ if(package == NULL) {
+ for(lp = groups; lp; lp = lp->next) {
+ pkg = pkg_ingroup(db, (char *)lp->data);
+ for(q = pkg; q; q = q->next) {
+ printf("%s %s\n", (char *)lp->data, (char *)q->data);
+ }
+ list_free(pkg);
+ }
+ } else {
+ if(!is_in(package, groups)) {
+ fprintf(stderr, "Group \"%s\" was not found.\n", package);
+ return(2);
+ }
+ pkg = pkg_ingroup(db, package);
+ for(q = pkg; q; q = q->next) {
+ printf("%s %s\n", package, (char *)q->data);
+ }
+ list_free(pkg);
+ }
+ list_free(groups);
+ continue;
+ }
+
/* output info for a .tar.gz package */
if(pmo_q_isfile) {
if(package == NULL) {
@@ -1479,11 +1926,86 @@ int pacman_query(pacdb_t *db, PMList *targets)
int pacman_upgrade(pacdb_t *db, PMList *targets)
{
/* this is basically just a remove-then-add process. pacman_add() will */
- /* handle it */
- pmo_upgrade = 1;
+ /* handle it */
+ pmo_upgrade = 1;
return(pacman_add(db, targets));
}
+/* Re-order a list of target packages with respect to their dependencies.
+ *
+ * Example:
+ * A depends on C
+ * B depends on A
+ * Target order is A,B,C,D
+ *
+ * Should be re-ordered to C,A,B,D
+ *
+ * This function returns the new PMList* target list.
+ *
+ */
+PMList* sortbydeps(PMList *targets)
+{
+ PMList *newtargs = NULL;
+ PMList *i, *j, *k;
+ int change = 1;
+ int numscans = 0;
+ int numtargs = 0;
+ int clean = 0;
+
+ /* count the number of targets */
+ for(i = targets; i; i = i->next, numtargs++);
+
+ while(change) {
+ change = 0;
+ if(numscans > numtargs) {
+ vprint("warning: possible dependency cycle detected\n");
+ change = 0;
+ continue;
+ }
+ newtargs = NULL;
+ numscans++;
+ /* run thru targets, moving up packages as necessary */
+ for(i = targets; i; i = i->next) {
+ pkginfo_t *p = (pkginfo_t*)i->data;
+ for(j = p->depends; j; j = j->next) {
+ depend_t dep;
+ int found = 0;
+ pkginfo_t *q = NULL;
+
+ splitdep(j->data, &dep);
+ /* look for dep.name -- if it's farther down in the list, then
+ * move it up above p
+ */
+ for(k = i->next; k && !found; k = k->next) {
+ q = (pkginfo_t*)k->data;
+ if(!strcmp(dep.name, q->name)) {
+ found = 1;
+ }
+ }
+ if(found) {
+ if(!is_pkgin(q, newtargs)) {
+ change = 1;
+ newtargs = list_add(newtargs, q);
+ }
+ }
+ }
+ if(!is_pkgin(p, newtargs)) {
+ newtargs = list_add(newtargs, p);
+ }
+ }
+ if(clean && change) {
+ /* free up targets -- it's local now */
+ for(i = targets; i; i = i->next) {
+ i->data = NULL;
+ }
+ list_free(targets);
+ }
+ targets = newtargs;
+ clean = 1;
+ }
+ return(targets);
+}
+
/* populates *list with packages that need to be installed to satisfy all
* dependencies (recursive) for *syncpkg->pkg
*
@@ -1504,17 +2026,23 @@ int resolvedeps(pacdb_t *local, PMList *databases, syncpkg_t *syncpkg, PMList *l
int found = 0;
depmissing_t *miss = (depmissing_t*)i->data;
- if(miss->type == CONFLICT) {
+ /* XXX: conflicts are now treated specially in the _add and _sync functions */
+
+ /*if(miss->type == CONFLICT) {
fprintf(stderr, "error: cannot resolve dependencies for \"%s\":\n", miss->target);
fprintf(stderr, " %s conflicts with %s\n", miss->target, miss->depend.name);
return(1);
- } else if(miss->type == DEPEND) {
+ } else*/
+ if(miss->type == DEPEND) {
syncpkg_t *sync = NULL;
MALLOC(sync, sizeof(syncpkg_t));
+ sync->replaces = NULL;
/* find the package in one of the repositories */
for(j = databases; !found && j; j = j->next) {
+ PMList *provides;
dbsync_t *dbs = (dbsync_t*)j->data;
+ /* check literals */
for(k = dbs->pkgcache; !found && k; k = k->next) {
pkginfo_t *pkg = (pkginfo_t*)k->data;
if(!strcmp(miss->depend.name, pkg->name)) {
@@ -1524,6 +2052,17 @@ int resolvedeps(pacdb_t *local, PMList *databases, syncpkg_t *syncpkg, PMList *l
sync->dbs = dbs;
}
}
+ /* check provides */
+ if(!found) {
+ provides = whatprovides(dbs->db, miss->depend.name);
+ if(provides) {
+ found = 1;
+ /* re-fetch the package record with dependency info */
+ sync->pkg = db_scan(dbs->db, provides->data, INFRQ_DESC | INFRQ_DEPENDS);
+ sync->dbs = dbs;
+ }
+ list_free(provides);
+ }
}
if(!found) {
fprintf(stderr, "error: cannot resolve dependencies for \"%s\":\n", miss->target);
@@ -1541,7 +2080,7 @@ int resolvedeps(pacdb_t *local, PMList *databases, syncpkg_t *syncpkg, PMList *l
/* this dep is already in the target list */
continue;
}
- /*printf("resolving %s\n", sync->pkg->name); fflush(stdout);*/
+ vprint("resolving %s\n", sync->pkg->name);
found = 0;
for(j = trail; j; j = j->next) {
syncpkg_t *tmp = (syncpkg_t*)j->data;
@@ -1554,11 +2093,11 @@ int resolvedeps(pacdb_t *local, PMList *databases, syncpkg_t *syncpkg, PMList *l
if(resolvedeps(local, databases, sync, list, trail)) {
return(1);
}
- vprint("adding %s-%s\n", sync->pkg->name, sync->pkg->version);
+ vprint("adding %s-%s\n", sync->pkg->name, sync->pkg->version);
list_add(list, sync);
} else {
/* cycle detected -- skip it */
- /*printf("cycle detected\n"); fflush(stdout);*/
+ vprint("dependency cycle detected: %s\n", sync->pkg->name);
}
}
}
@@ -1618,8 +2157,13 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
}
}
if(found == 0) {
- /* not found */
- continue;
+ /* look for packages that list depend.name as a "provide" */
+ PMList *provides = whatprovides(db, depend.name);
+ if(provides == NULL) {
+ /* not found */
+ continue;
+ }
+ /* we found an installed package that provides depend.name */
}
found = 0;
if(depend.mod == DEP_ANY) {
@@ -1647,7 +2191,9 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
strncpy(miss->target, p->name, 256);
strncpy(miss->depend.name, depend.name, 256);
strncpy(miss->depend.version, depend.version, 64);
- baddeps = list_add(baddeps, miss);
+ if(!list_isin(baddeps, miss)) {
+ baddeps = list_add(baddeps, miss);
+ }
}
}
freepkg(oldpkg);
@@ -1673,7 +2219,9 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
miss->depend.version[0] = '\0';
strncpy(miss->target, tp->name, 256);
strncpy(miss->depend.name, dp->name, 256);
- baddeps = list_add(baddeps, miss);
+ if(!list_isin(baddeps, miss)) {
+ baddeps = list_add(baddeps, miss);
+ }
}
}
/* check targets against targets */
@@ -1686,7 +2234,9 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
miss->depend.version[0] = '\0';
strncpy(miss->target, tp->name, 256);
strncpy(miss->depend.name, a->name, 256);
- baddeps = list_add(baddeps, miss);
+ if(!list_isin(baddeps, miss)) {
+ baddeps = list_add(baddeps, miss);
+ }
}
}
}
@@ -1701,21 +2251,45 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
miss->depend.version[0] = '\0';
strncpy(miss->target, tp->name, 256);
strncpy(miss->depend.name, info->name, 256);
+ if(!list_isin(baddeps, miss)) {
+ baddeps = list_add(baddeps, miss);
+ }
+ }
+ }
+ }
+
+ /* PROVIDES -- check to see if another package already provides what
+ * we offer
+ */
+ for(j = tp->provides; j; j = j->next) {
+ PMList *provs = whatprovides(db, j->data);
+ for(k = provs; k; k = k->next) {
+ if(!strcmp(tp->name, k->data)) {
+ /* this is the same package -- skip it */
+ continue;
+ }
+ /* we treat this just like a conflict */
+ MALLOC(miss, sizeof(depmissing_t));
+ miss->type = CONFLICT;
+ miss->depend.mod = DEP_ANY;
+ miss->depend.version[0] = '\0';
+ strncpy(miss->target, tp->name, 256);
+ strncpy(miss->depend.name, k->data, 256);
+ if(!list_isin(baddeps, miss)) {
baddeps = list_add(baddeps, miss);
}
}
}
- /* DEPENDENCIES */
- /* cycle thru this targets dependency list */
+ /* DEPENDENCIES -- look for unsatisfied dependencies */
for(j = tp->depends; j; j = j->next) {
/* split into name/version pairs */
if(splitdep((char*)j->data, &depend)) {
- fprintf(stderr, "warning: invalid dependency in %s\n", (char*)tp->name);
+ logaction("warning: invalid dependency in %s\n", (char*)tp->name);
continue;
}
found = 0;
- /* check database */
+ /* check database for literal packages */
for(k = pm_packages; k && !found; k = k->next) {
pkginfo_t *p = (pkginfo_t*)k->data;
if(!strcmp(p->name, depend.name)) {
@@ -1745,7 +2319,8 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
/* check other targets */
for(k = targets; k && !found; k = k->next) {
pkginfo_t *p = (pkginfo_t*)k->data;
- if(!strcmp(p->name, depend.name)) {
+ /* see if the package names match OR if p provides depend.name */
+ if(!strcmp(p->name, depend.name) || is_in(depend.name, p->provides)) {
if(depend.mod == DEP_ANY) {
/* accept any version */
found = 1;
@@ -1768,10 +2343,45 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
FREE(ver);
}
}
- /* TODO: switch positions in targets if one package should precede
- * the other (wrt deps)
- */
}
+ /* check database for provides matches */
+ if(!found){
+ k = whatprovides(db, depend.name);
+ if(k) {
+ /* grab the first one (there should only really be one, anyway) */
+ pkginfo_t *p = db_scan(db, k->data, INFRQ_DESC);
+ if(p == NULL) {
+ /* wtf */
+ fprintf(stderr, "data error: %s supposedly provides %s, but it was not found in db\n",
+ (char*)k->data, depend.name);
+ list_free(k);
+ continue;
+ }
+ if(depend.mod == DEP_ANY) {
+ /* accept any version */
+ found = 1;
+ } else {
+ char *ver = strdup(p->version);
+ /* check for a release in depend.version. if it's
+ * missing remove it from p->version as well.
+ */
+ if(!index(depend.version,'-')) {
+ char *ptr;
+ for(ptr = ver; *ptr != '-'; ptr++);
+ *ptr = '\0';
+ }
+ cmp = rpmvercmp(ver, depend.version);
+ switch(depend.mod) {
+ case DEP_EQ: found = (cmp == 0); break;
+ case DEP_GE: found = (cmp >= 0); break;
+ case DEP_LE: found = (cmp <= 0); break;
+ }
+ FREE(ver);
+ }
+ }
+ list_free(k);
+ }
+ /* else if still not found... */
if(!found) {
MALLOC(miss, sizeof(depmissing_t));
miss->type = DEPEND;
@@ -1779,7 +2389,9 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
strncpy(miss->target, tp->name, 256);
strncpy(miss->depend.name, depend.name, 256);
strncpy(miss->depend.version, depend.version, 64);
- baddeps = list_add(baddeps, miss);
+ if(!list_isin(baddeps, miss)) {
+ baddeps = list_add(baddeps, miss);
+ }
}
}
}
@@ -1799,7 +2411,9 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets)
miss->depend.version[0] = '\0';
strncpy(miss->target, tp->name, 256);
strncpy(miss->depend.name, (char*)j->data, 256);
- baddeps = list_add(baddeps, miss);
+ if(!list_isin(baddeps, miss)) {
+ baddeps = list_add(baddeps, miss);
+ }
}
}
}
@@ -1896,6 +2510,7 @@ int parseargs(int op, int argc, char **argv)
{"vertest", no_argument, 0, 'Y'},
{"resolve", no_argument, 0, 'D'},
{"root", required_argument, 0, 'r'},
+ {"dbpath", required_argument, 0, 'b'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
@@ -1912,10 +2527,11 @@ int parseargs(int op, int argc, char **argv)
{"downloadonly", no_argument, 0, 'w'},
{"refresh", no_argument, 0, 'y'},
{"cascade", no_argument, 0, 'c'},
+ {"groups", no_argument, 0, 'g'},
{0, 0, 0, 0}
};
- while((opt = getopt_long(argc, argv, "ARUFQSTDYr:vhscVfnoldpiuwy", opts, &option_index))) {
+ while((opt = getopt_long(argc, argv, "ARUFQSTDYr:b:vhscVfnoldpiuwyg", opts, &option_index))) {
if(opt < 0) {
break;
}
@@ -1945,10 +2561,12 @@ int parseargs(int op, int argc, char **argv)
case 'y': pmo_s_sync = 1; break;
case 's': pmo_s_search = 1; break;
case 'c': pmo_s_clean = 1; pmo_r_cascade = 1; break;
+ case 'g': pmo_group = 1; break;
case 'r': if(realpath(optarg, pmo_root) == NULL) {
perror("bad root path");
return(1);
} break;
+ case 'b': strcpy(pmo_dbpath, optarg); break;
case '?': return(1);
default: return(1);
}
@@ -2040,6 +2658,9 @@ int parseconfig(char *configfile)
if(!strcmp(key, "NOPASSIVEFTP")) {
pmo_nopassiveftp = 1;
vprint("config: nopassiveftp\n");
+ } else if(!strcmp(key, "USESYSLOG")) {
+ pmo_usesyslog = 1;
+ vprint("config: usesyslog\n");
} else {
fprintf(stderr, "config: line %d: syntax error\n", linenum);
return(1);
@@ -2090,7 +2711,7 @@ int parseconfig(char *configfile)
MALLOC(server, sizeof(server_t));
server->server = server->path = NULL;
- server->islocal = 0;
+ server->protocol = NULL;
p = strstr(ptr, "://");
if(p == NULL) {
@@ -2103,8 +2724,8 @@ int parseconfig(char *configfile)
fprintf(stderr, "config: line %d: bad server location\n", linenum);
return(1);
}
- server->islocal = !strcmp(ptr, "local");
- if(!server->islocal) {
+ server->protocol = strdup(ptr);
+ if(strcmp(server->protocol, "file")) {
char *slash;
/* no http support yet */
if(strcmp(ptr, "ftp")) {
@@ -2160,18 +2781,18 @@ int parseconfig(char *configfile)
void usage(int op, char *myname)
{
if(op == PM_MAIN) {
- printf("usage: %s {-h --help}\n", myname);
- printf(" %s {-V --version}\n", myname);
- printf(" %s {-A --add} [options] <file>\n", myname);
- printf(" %s {-R --remove} [options] <package>\n", myname);
- printf(" %s {-U --upgrade} [options] <file>\n", myname);
- printf(" %s {-F --freshen} [options] <file>\n", myname);
- printf(" %s {-Q --query} [options] [package]\n", myname);
- printf(" %s {-S --sync} [options] [package]\n", myname);
+ printf("usage: %s {-h --help}\n", myname);
+ printf(" %s {-V --version}\n", myname);
+ printf(" %s {-A --add} [options] <file>\n", myname);
+ printf(" %s {-R --remove} [options] <package>\n", myname);
+ printf(" %s {-U --upgrade} [options] <file>\n", myname);
+ printf(" %s {-F --freshen} [options] <file>\n", myname);
+ printf(" %s {-Q --query} [options] [package]\n", myname);
+ printf(" %s {-S --sync} [options] [package]\n", myname);
printf("\nuse '%s --help' with other options for more syntax\n\n", myname);
} else {
if(op == PM_ADD) {
- printf("usage: %s {-A --add} [options] <file>\n", myname);
+ printf("usage: %s {-A --add} [options] <file>\n", myname);
printf("options:\n");
printf(" -d, --nodeps skip dependency checks\n");
printf(" -f, --force force install, overwrite conflicting files\n");
@@ -2194,6 +2815,7 @@ void usage(int op, char *myname)
printf("usage: %s {-Q --query} [options] [package]\n", myname);
printf("options:\n");
printf(" -i, --info view package information\n");
+ printf(" -g, --groups view all members of a package group\n");
printf(" -l, --list list the contents of the queried package\n");
printf(" -o, --owns <file> query the package that owns <file>\n");
printf(" -p, --file pacman will query the package file [package] instead of\n");
@@ -2204,6 +2826,7 @@ void usage(int op, char *myname)
printf(" -c, --clean remove packages from cache directory to free up diskspace\n");
printf(" -d, --nodeps skip dependency checks\n");
printf(" -f, --force force install, overwrite conflicting files\n");
+ printf(" -g, --groups view all members of a package group\n");
printf(" -s, --search search sync database for matching strings\n");
printf(" -u, --sysupgrade upgrade all packages that are out of date\n");
printf(" -w, --downloadonly download packages, but do not install/upgrade anything\n");
@@ -2211,6 +2834,7 @@ void usage(int op, char *myname)
}
printf(" -v, --verbose be verbose\n");
printf(" -r, --root <path> set an alternate installation root\n");
+ printf(" -b, --dbpath <path> set an alternate database location\n");
}
}
@@ -2218,18 +2842,18 @@ void usage(int op, char *myname)
*/
void version(void)
{
- printf("\n");
- printf(" .--. Pacman v%s\n", PACVER);
- printf("/ _.-' .-. .-. .-. Copyright (C) 2002 Judd Vinet <jvinet@zeroflux.org>\n");
- printf("\\ '-. '-' '-' '-' \n");
- printf(" '--' This program may be freely redistributed under\n");
- printf(" the terms of the GNU GPL\n\n");
+ printf("\n");
+ printf(" .--. Pacman v%s\n", PACVER);
+ printf("/ _.-' .-. .-. .-. Copyright (C) 2002-2003 Judd Vinet <jvinet@zeroflux.org>\n");
+ printf("\\ '-. '-' '-' '-' \n");
+ printf(" '--' This program may be freely redistributed under\n");
+ printf(" the terms of the GNU General Public License\n\n");
}
/* Check verbosity option and, if set, print the
* string to stdout
*/
-int vprint(char *fmt, ...)
+void vprint(char *fmt, ...)
{
va_list args;
if(pmo_verbose) {
@@ -2238,9 +2862,47 @@ int vprint(char *fmt, ...)
va_end(args);
fflush(stdout);
}
- return(0);
}
+/* Output a message to stderr, and (optionally) syslog */
+void logaction(char *fmt, ...)
+{
+ char msg[1024];
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(msg, 1024, fmt, args);
+ va_end(args);
+
+ fprintf(stderr, "%s", msg);
+ if(pmo_usesyslog) {
+ syslog(LOG_WARNING, "%s", msg);
+ }
+}
+
+/* Condense a list of strings into one long (space-delimited) string
+ */
+char* buildstring(PMList *strlist)
+{
+ char* str;
+ int size = 1;
+ PMList *lp;
+
+ for(lp = strlist; lp; lp = lp->next) {
+ size += strlen(lp->data) + 1;
+ }
+ MALLOC(str, size);
+ str[0] = '\0';
+ for(lp = strlist; lp; lp = lp->next) {
+ strcat(str, lp->data);
+ strcat(str, " ");
+ }
+ /* shave off the last space */
+ str[strlen(str)-1] = '\0';
+
+ return(str);
+}
+
+
int lckmk(char *file, int retries, unsigned int sleep_secs)
{
int fd, count = 0;
@@ -2263,13 +2925,16 @@ int lckrm(char *file)
void cleanup(int signum)
{
if(pm_access == READ_WRITE && lckrm(lckfile)) {
- fprintf(stderr, "warning: could not remove lock file %s\n", lckfile);
+ logaction("warning: could not remove lock file %s\n", lckfile);
}
if(workfile) {
/* remove the current file being downloaded (as it's not complete) */
unlink(workfile);
FREE(workfile);
}
+ if(pmo_usesyslog) {
+ closelog();
+ }
exit(signum);
}
diff --git a/src/pacman.h b/src/pacman.h
index 3d749886..2dd0a9db 100644
--- a/src/pacman.h
+++ b/src/pacman.h
@@ -1,5 +1,5 @@
/*
- * pacman
+ * pacman.h
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*
@@ -22,7 +22,7 @@
#define _PAC_PACMAN_H
#ifndef PACVER
-#define PACVER "2.5.1"
+#define PACVER "2.6"
#endif
#ifndef PKGDIR
@@ -51,6 +51,7 @@ int pacman_query(pacdb_t *db, PMList *targets);
int pacman_sync(pacdb_t *db, PMList *targets);
int pacman_deptest(pacdb_t *db, PMList *targets);
+PMList* sortbydeps(PMList *targets);
PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets);
int resolvedeps(pacdb_t *local, PMList *databases, syncpkg_t *sync, PMList *list, PMList *trail);
int splitdep(char *depstr, depend_t *depend);
@@ -62,7 +63,9 @@ int parseconfig(char *configfile);
void usage(int op, char *myname);
void version(void);
-int vprint(char *fmt, ...);
+void vprint(char *fmt, ...);
+void logaction(char *fmt, ...);
+char* buildstring(PMList *strlist);
int lckmk(char *file, int retries, unsigned int sleep_secs);
int lckrm(char *lckfile);
void cleanup(int signum);
diff --git a/src/pacsync.c b/src/pacsync.c
index 91e62117..3d87013a 100644
--- a/src/pacsync.c
+++ b/src/pacsync.c
@@ -1,5 +1,5 @@
/*
- * pacman
+ * pacsync.c
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*
@@ -21,6 +21,7 @@
#include "config.h"
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -39,10 +40,12 @@ static int offset;
/* pacman options */
extern char *pmo_root;
+extern char *pmo_dbpath;
extern unsigned short pmo_nopassiveftp;
/* sync servers */
extern PMList *pmc_syncs;
+extern int maxcols;
int sync_synctree()
{
@@ -52,10 +55,10 @@ int sync_synctree()
PMList *files = NULL;
PMList *i;
int success = 0;
-
+
for(i = pmc_syncs; i; i = i->next) {
sync_t *sync = (sync_t*)i->data;
- snprintf(ldir, PATH_MAX, "%s%s", pmo_root, PKGDIR);
+ snprintf(ldir, PATH_MAX, "%s%s", pmo_root, pmo_dbpath);
/* build a one-element list */
snprintf(path, PATH_MAX, "%s.db.tar.gz", sync->treename);
@@ -66,13 +69,12 @@ int sync_synctree()
fprintf(stderr, "failed to synchronize %s\n", sync->treename);
success = 0;
}
- /*printf("\n");*/
list_free(files);
files = NULL;
snprintf(path, PATH_MAX, "%s/%s.db.tar.gz", ldir, sync->treename);
if(success) {
- snprintf(ldir, PATH_MAX, "%s%s/%s", pmo_root, PKGDIR, sync->treename);
+ snprintf(ldir, PATH_MAX, "%s%s/%s", pmo_root, pmo_dbpath, sync->treename);
/* remove the old dir */
vprint("removing %s (if it exists)\n", ldir);
rmrf(ldir);
@@ -111,7 +113,7 @@ int downloadfiles(PMList *servers, char *localpath, PMList *files)
for(i = servers; i && !done; i = i->next) {
server_t *server = (server_t*)i->data;
- if(!server->islocal) {
+ if(!strcmp(server->protocol, "ftp")) {
FtpInit();
if(!FtpConnect(server->server, &control)) {
fprintf(stderr, "error: cannot connect to %s\n", server->server);
@@ -153,50 +155,42 @@ int downloadfiles(PMList *servers, char *localpath, PMList *files)
sync_fnm[j] = ' ';
}
sync_fnm[24] = '\0';
+ offset = 0;
- if(!server->islocal) {
- int tries = 2;
- while(tries) {
- if(!FtpSize(fn, &fsz, FTPLIB_IMAGE, control)) {
- fprintf(stderr, "warning: failed to get filesize for %s\n", fn);
- }
- offset = 0;
- if(!stat(output, &st)) {
- offset = (int)st.st_size;
- }
- if(offset) {
- if(!FtpRestart(offset, control)) {
- fprintf(stderr, "warning: failed to resume download -- restarting\n");
- /* can't resume: */
- /* unlink the file in order to restart download from scratch */
- unlink(output);
- }
+ if(!strcmp(server->protocol, "ftp")) {
+ if(!FtpSize(fn, &fsz, FTPLIB_IMAGE, control)) {
+ fprintf(stderr, "warning: failed to get filesize for %s\n", fn);
+ }
+ if(!stat(output, &st)) {
+ offset = (int)st.st_size;
+ if(!FtpRestart(offset, control)) {
+ fprintf(stderr, "warning: failed to resume download -- restarting\n");
+ /* can't resume: */
+ /* unlink the file in order to restart download from scratch */
+ unlink(output);
}
- /* set up our progress bar's callback */
- FtpOptions(FTPLIB_CALLBACK, (long)log_progress, control);
- FtpOptions(FTPLIB_IDLETIME, (long)1000, control);
- FtpOptions(FTPLIB_CALLBACKARG, (long)&fsz, control);
- FtpOptions(FTPLIB_CALLBACKBYTES, (10*1024), control);
+ }
+ /* set up our progress bar's callback */
+ FtpOptions(FTPLIB_CALLBACK, (long)log_progress, control);
+ FtpOptions(FTPLIB_IDLETIME, (long)1000, control);
+ FtpOptions(FTPLIB_CALLBACKARG, (long)&fsz, control);
+ FtpOptions(FTPLIB_CALLBACKBYTES, (10*1024), control);
- if(!FtpGet(output, lp->data, FTPLIB_IMAGE, control)) {
- fprintf(stderr, "\nfailed downloading %s from %s: %s\n",
- fn, server->server, FtpLastResponse(control));
- /* we leave the partially downloaded file in place so it can be resumed later */
- /* try each file twice in case it was just one of those transient network errors */
- tries--;
- } else {
- char completefile[PATH_MAX];
- log_progress(control, fsz-offset, &fsz);
- complete = list_add(complete, fn);
- tries = 0;
- /* rename "output.part" file to "output" file */
- snprintf(completefile, PATH_MAX, "%s/%s", localpath, fn);
- rename(output, completefile);
- }
- printf("\n");
- fflush(stdout);
+ if(!FtpGet(output, lp->data, FTPLIB_IMAGE, control)) {
+ fprintf(stderr, "\nfailed downloading %s from %s: %s\n",
+ fn, server->server, FtpLastResponse(control));
+ /* we leave the partially downloaded file in place so it can be resumed later */
+ } else {
+ char completefile[PATH_MAX];
+ log_progress(control, fsz-offset, &fsz);
+ complete = list_add(complete, fn);
+ /* rename "output.part" file to "output" file */
+ snprintf(completefile, PATH_MAX, "%s/%s", localpath, fn);
+ rename(output, completefile);
}
- } else {
+ printf("\n");
+ fflush(stdout);
+ } else if(!strcmp(server->protocol, "file")) {
/* local repository, just copy the file */
char src[PATH_MAX], dest[PATH_MAX];
snprintf(src, PATH_MAX, "%s%s", server->path, fn);
@@ -206,10 +200,10 @@ int downloadfiles(PMList *servers, char *localpath, PMList *files)
fprintf(stderr, "failed copying %s\n", src);
} else {
char out[56];
- printf("%s [", sync_fnm);
+ printf(" %s [", sync_fnm);
strncpy(out, server->path, 33);
printf("%s", out);
- for(j = strlen(out); j < 33; j++) {
+ for(j = strlen(out); j < maxcols-44; j++) {
printf(" ");
}
fputs("] 100% | LOCAL\n", stdout);
@@ -223,7 +217,7 @@ int downloadfiles(PMList *servers, char *localpath, PMList *files)
done = 1;
}
- if(!server->islocal) {
+ if(!strcmp(server->protocol, "ftp")) {
FtpQuit(control);
}
}
@@ -235,37 +229,44 @@ static int log_progress(netbuf *ctl, int xfered, void *arg)
{
int fsz = *(int*)arg;
int pct = ((float)(xfered+offset) / fsz) * 100;
- int i;
+ int i, cur;
+ char *cenv = NULL;
- printf("%s [", sync_fnm);
- for(i = 0; i < (int)(pct/3); i++) {
- printf("#");
+ cenv = getenv("COLUMNS");
+ if(cenv) {
+ maxcols = atoi(cenv);
}
- for(i = (int)(pct/3); i < (int)(100/3); i++) {
- printf(" ");
+
+ printf(" %s [", sync_fnm);
+ cur = (int)((maxcols-44)*pct/100);
+ for(i = 0; i < maxcols-44; i++) {
+ (i < cur) ? printf("#") : printf(" ");
}
- printf("] %3d%% | %6dK\r ", pct, ((xfered+offset)/1024));
+ printf("] %3d%% | %6dK\r", pct, ((xfered+offset)/1024));
fflush(stdout);
return(1);
}
-/* Test for existence of a package in a PMList*
- * of syncpkg_t*
+/* Test for existance of a package in a PMList* of syncpkg_t*
+ * If found, return a pointer to the respective syncpkg_t*
*/
-int is_pkginsync(syncpkg_t *needle, PMList *haystack)
+syncpkg_t* find_pkginsync(char *needle, PMList *haystack)
{
- PMList *lp;
+ PMList *i;
syncpkg_t *sync;
int found = 0;
- for(lp = haystack; lp && !found; lp = lp->next) {
- sync = (syncpkg_t*)lp->data;
- if(sync && !strcmp(sync->pkg->name, needle->pkg->name)) {
+ for(i = haystack; i && !found; i = i->next) {
+ sync = (syncpkg_t*)i->data;
+ if(sync && !strcmp(sync->pkg->name, needle)) {
found = 1;
}
}
+ if(!found) {
+ sync = NULL;
+ }
- return found;
+ return sync;
}
/* vim: set ts=2 sw=2 noet: */
diff --git a/src/pacsync.h b/src/pacsync.h
index abb657f8..fe9b5ba3 100644
--- a/src/pacsync.h
+++ b/src/pacsync.h
@@ -1,5 +1,5 @@
/*
- * pacman
+ * pacsync.h
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*
@@ -23,7 +23,7 @@
/* Servers */
typedef struct __server_t {
- unsigned short islocal;
+ char* protocol;
char* server;
char* path;
} server_t;
@@ -44,11 +44,12 @@ typedef struct __dbsync_t {
typedef struct __syncpkg_t {
pkginfo_t *pkg;
dbsync_t *dbs;
+ PMList *replaces;
} syncpkg_t;
int sync_synctree();
int downloadfiles(PMList *servers, char *localpath, PMList *files);
-int is_pkginsync(syncpkg_t *needle, PMList *haystack);
+syncpkg_t* find_pkginsync(char *needle, PMList *haystack);
#endif
diff --git a/src/rpmvercmp.c b/src/rpmvercmp.c
index de4aefe2..7805be0c 100644
--- a/src/rpmvercmp.c
+++ b/src/rpmvercmp.c
@@ -1,5 +1,5 @@
/*
- * pacman
+ * rpmvercmp.c
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*
diff --git a/src/rpmvercmp.h b/src/rpmvercmp.h
index 3b7df650..ab5594d8 100644
--- a/src/rpmvercmp.h
+++ b/src/rpmvercmp.h
@@ -1,5 +1,5 @@
/*
- * pacman
+ * rpmvercmp.h
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*
diff --git a/src/util.c b/src/util.c
index cd7978e9..32852816 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1,5 +1,5 @@
/*
- * pacman
+ * util.c
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*
@@ -117,6 +117,7 @@ int copyfile(char *src, char *dest)
return(0);
}
+/* does the same thing as 'mkdir -p' */
int makepath(char *path)
{
char *orig, *str, *ptr;
@@ -146,6 +147,7 @@ int makepath(char *path)
return(0);
}
+/* does the same thing as 'rm -rf' */
int rmrf(char *path)
{
int errflag = 0;
@@ -157,13 +159,13 @@ int rmrf(char *path)
if(!unlink(path)) {
return(0);
} else {
- if (errno == ENOENT) {
+ if(errno == ENOENT) {
return(0);
- } else if (errno == EPERM) {
+ } else if(errno == EPERM) {
/* fallthrough */
- } else if (errno == EISDIR) {
+ } else if(errno == EISDIR) {
/* fallthrough */
- } else if (errno == ENOTDIR) {
+ } else if(errno == ENOTDIR) {
return(1);
} else {
/* not a directory */
@@ -174,7 +176,7 @@ int rmrf(char *path)
return(1);
}
for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
- if (dp->d_ino) {
+ if(dp->d_ino) {
sprintf(name, "%s/%s", path, dp->d_name);
if(strcmp(dp->d_name, "..") && strcmp(dp->d_name, ".")) {
errflag += rmrf(name);
@@ -190,6 +192,7 @@ int rmrf(char *path)
return(0);
}
+/* presents a prompt and gets a Y/N answer */
int yesno(char *fmt, ...)
{
char response[32];
diff --git a/src/util.h b/src/util.h
index be2c6089..7c1556aa 100644
--- a/src/util.h
+++ b/src/util.h
@@ -1,5 +1,5 @@
/*
- * pacman
+ * util.h
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*
diff --git a/src/vercmp.c b/src/vercmp.c
index 43f8deab..25172086 100644
--- a/src/vercmp.c
+++ b/src/vercmp.c
@@ -1,5 +1,5 @@
/*
- * pacman
+ * vercmp.c
*
* Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
*