From 6a654187b68d37211dc8af301e611ec4a7f132c4 Mon Sep 17 00:00:00 2001 From: Judd Vinet Date: Mon, 16 Sep 2002 05:22:13 +0000 Subject: Imported from pacman-2.1.tar.gz --- Makefile.in | 6 +- TODO | 17 +- doc/pacman.8.in | 66 +++++-- etc/pacman.conf | 96 +++++++--- etc/supfile | 23 --- etc/supfile.arch | 23 +++ etc/supfile.unofficial | 16 ++ scripts/abs | 13 +- scripts/gensync | 104 +++++++++++ scripts/makepkg | 130 +++++++------- scripts/makeworld | 57 +++--- scripts/pacsync | 2 +- src/db.c | 1 + src/list.c | 12 ++ src/list.h | 1 + src/package.c | 1 + src/pacman.c | 462 +++++++++++++++++++++++++++++++------------------ src/pacman.h | 4 +- src/pacsync.c | 230 ++++++++++++++---------- src/pacsync.h | 25 ++- src/util.c | 145 +++++++++++++--- 21 files changed, 980 insertions(+), 454 deletions(-) delete mode 100644 etc/supfile create mode 100644 etc/supfile.arch create mode 100644 etc/supfile.unofficial create mode 100755 scripts/gensync diff --git a/Makefile.in b/Makefile.in index e2c4798b..07e5d802 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.0 +PACVER = 2.1 LIBTAR_VERSION = 1.2.5 TOPDIR = @srcdir@ @@ -105,11 +105,13 @@ install: pacman convertdb man $(INSTALL) -D -m0755 $(SCRDIR)makepkg $(DESTDIR)$(BINDIR)/makepkg $(INSTALL) -D -m0755 $(SCRDIR)makeworld $(DESTDIR)$(BINDIR)/makeworld $(INSTALL) -D -m0755 $(SCRDIR)abs $(DESTDIR)$(BINDIR)/abs + $(INSTALL) -D -m0755 $(SCRDIR)gensync $(DESTDIR)$(BINDIR)/gensync $(INSTALL) -D -m0644 $(MANSRC)pacman.8 $(DESTDIR)$(MANDIR)/man8/pacman.8 $(INSTALL) -D -m0644 $(MANSRC)makepkg.8 $(DESTDIR)$(MANDIR)/man8/makepkg.8 $(INSTALL) -D -m0644 etc/pacman.conf $(DESTDIR)/etc/pacman.conf $(INSTALL) -D -m0644 etc/makepkg.conf $(DESTDIR)/etc/makepkg.conf - $(INSTALL) -D -m0644 etc/supfile $(DESTDIR)/etc/abs/supfile + $(INSTALL) -D -m0644 etc/supfile.arch $(DESTDIR)/etc/abs/supfile.arch + $(INSTALL) -D -m0644 etc/supfile.unofficial $(DESTDIR)/etc/abs/supfile.unofficial clean: rm -f *~ $(OBJDIR)*.o $(MANSRC)*.8 diff --git a/TODO b/TODO index 5dde8fdb..2e4c64e6 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,14 @@ +- have "group" designations +- use 'set -e' in makepkg? +- if a package fails, ask before aborting the full operation +- ask, then remove conflicting packages with --sync +- use a provides tag (instead of an OR operator in depends) +- add a freshen operation +- add a 'cascade' option to --remove that will remove a package and + all requiredby packages under it - check $PACCONF env var - ftp transfer progress bar breaks after ~42000 K - use a 'trust pacman' config option for downgrading? -- use a provides tag (instead of an OR operator in depends) - instead of 'conflicts' use a ! operator in depends - add a --pretend option - add a consistency/sanity check operation @@ -11,12 +18,10 @@ - use package caches more for performance + add an "ignore package" option in either pacman.conf or in each package record. this will prevent it from being upgraded from the sync set +- if a package is removed with --nodeps and re-installed, the requiredby + fields of it's required packages are not updated - duplicate dep checks occur with sync (one in sync, one in add) - clean up output a bit (message queue?) -- add an OR operator to dependencies or allow a sibling tag (ie, mawk, gawk) - run ldd on every executable in a newly built package to find required so's -- add a freshen operation -- allow multiple ftp servers to be defined and fallback to backups on failure - use a files.cache gdbm (or whatever) for --owns and db_find_conflicts -- things like 'groupadd' and 'useradd' in the install scriptlets will affect - the real root, not the one specified with -r + diff --git a/doc/pacman.8.in b/doc/pacman.8.in index dd3da750..d8bb26b7 100644 --- a/doc/pacman.8.in +++ b/doc/pacman.8.in @@ -1,4 +1,4 @@ -.TH pacman 8 "July 18, 2002" "pacman #VERSION#" "" +.TH pacman 8 "August 18, 2002" "pacman #VERSION#" "" .SH NAME pacman \- package manager utility .SH SYNOPSIS @@ -149,21 +149,55 @@ All three files are different. So we install the new file, but back up the old one to a .pacsave extension. This way the user can move the old configuration file back into place if he wishes. .SH CONFIGURATION -pacman will attempt to read \fI/etc/pacman.conf\fP each time it is invoked. Currently -the only options in it are for the --sync operation, but more may be added later. -.TP -.B "Sync_Tree_Name" -Sets the name of the package set you wish to follow. The common choices are \fIcurrent\fP -and \fIstable\fP. You could also specify a specific package version, eg, 0.3. -.TP -.B "Sync_Server" -This is the hostname of the ftp server that will be used for downloading lists and -packages. eg, \fIftp.ibiblio.org\fP. -.TP -.B "Sync_Tree_Path" -This is the full path name (on the ftp server) to the package tree you are following. -So if you are following \fIcurrent\fP, on \fIftp.ibiblio.org\fP, you would use -\fI/pub/linux/distributions/archlinux/current\fP. +pacman will attempt to read \fI/etc/pacman.conf\fP each time it is invoked. This +configuration file is divided into sections or \fIrepositories\fP. Each section +defines a package repository that pacman can use when searching for packages in +--sync mode. The exception to this is the \fIoptions\fP section, which defines +global options. +.TP +.SH Example: +.RS +.nf +[options] +NoUpgrade = etc/passed etc/group etc/shadow +NoUpgrade = etc/fstab + +[current] +Server = ftp://ftp.server.org/linux/archlinux/current +Server = ftp://ftp.mirror.com/arch/current + +[custom] +Server = local:///home/pkgs + +.fi +.RE +All files listed with a \fINoUpgrade\fP directive will never be touched during a package +install/upgrade. This directive is only valid in the options section. + +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 +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 +files are all in \fI/usr/abs/local\fP. All you need to do is generate a compressed package database +in the \fI/home/pkgs\fP directory so pacman can find it when run with --refresh. + +.RS +.nf +# gensync /usr/abs/local /home/pkgs/custom.db.tar.gz +.fi +.RE + +The above command will read all PKGBUILD files in /usr/abs/local and generate a compressed +database called /home/pkgs/custom.db.tar.gz. Note that the database must be of the form +\fI{treename}.db.tar.gz\fP, where {treename} is the name of the section defined in the +configuration file. +That's it! Now configure your \fIcustom\fP section in the configuration file as shown in the +config example above. Pacman will now use your package repository. If you add new packages to +the repository, remember to re-generate the database and use pacman's --refresh option. .SH SEE ALSO \fBmakepkg\fP is the package-building tool that comes with pacman. .SH AUTHOR diff --git a/etc/pacman.conf b/etc/pacman.conf index 8ffb78b5..c0b833b6 100644 --- a/etc/pacman.conf +++ b/etc/pacman.conf @@ -2,34 +2,78 @@ # /etc/pacman.conf # -# name of the tree you want to follow (eg: stable, current, 0.2, 0.3, ...) -Sync_Tree_Name = current +# Currently the only option directive is NoUpgrade. Use this with a +# space-delimited list of files that should never be touched by pacman +# during an install/upgrade. (note: do not include the leading slash) +[options] +NoUpgrade = etc/passwd etc/group etc/shadow +NoUpgrade = etc/fstab -# ftp server -Sync_Server = ftp.ibiblio.org +[current] +Server = ftp://ftp.ibiblio.org/pub/linux/distributions/archlinux/current +Server = ftp://ftp.mpi-sb.mpg.de/pub/linux/mirror/ftp.ibiblio.org/pub/Linux/distributions/archlinux/current +Server = ftp://ftp.oit.unc.edu/pub/Linux/distributions/archlinux/current +Server = ftp://ftp.tu-chemnitz.de/pub/linux/sunsite.unc-mirror/distributions/archlinux/current +Server = ftp://gd.tuwien.ac.at/opsys/linux/archlinux/current +Server = ftp://ftp2.archlinux.org/current +Server = ftp://ftp3.archlinux.org/current +Server = ftp://ftp.archlinux.org/current -# full path to sync tree -Sync_Tree_Path = /pub/linux/distributions/archlinux/current - -### -### MIRRORS -######################### - -# Sync_Server = ftp.mpi-sb.mpg.de -# Sync_Tree_Path = /pub/linux/mirror/ftp.ibiblio.org/pub/Linux/distributions/archlinux/current - -# Sync_Server = ftp2.archlinux.org -# Sync_Tree_Path = /current - -# Sync_Server = ftp.oit.unc.edu -# Sync_Tree_Path = /pub/Linux/distributions/archlinux/current - -# Sync_Server = ftp.tu-chemnitz.de -# Sync_Tree_Path = /pub/linux/sunsite.unc-mirror/distributions/archlinux/current +# Uncomment this block to access the 'unofficial' package set +# +#[unofficial] +#Server = ftp://ftp.ibiblio.org/pub/linux/distributions/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://gd.tuwien.ac.at/opsys/linux/archlinux/unofficial +#Server = ftp://ftp2.archlinux.org/unofficial +#Server = ftp://ftp3.archlinux.org/unofficial +#Server = ftp://ftp.archlinux.org/unofficial -# Sync_Server = ftp.archlinux.org -# Sync_Tree_Path = /current +# If you use the 'stable' tree, you should disable the 'current' +# tree to avoid conflicts +# +#[stable] +#Server = ftp://ftp.ibiblio.org/pub/linux/distributions/archlinux/stable +#Server = ftp://ftp.mpi-sb.mpg.de/pub/linux/mirror/ftp.ibiblio.org/pub/Linux/distributions/archlinux/stable +#Server = ftp://ftp.oit.unc.edu/pub/Linux/distributions/archlinux/stable +#Server = ftp://ftp.tu-chemnitz.de/pub/linux/sunsite.unc-mirror/distributions/archlinux/stable +#Server = ftp://ftp.archlinux.org/stable +#Server = ftp://ftp.oit.unc.edu/pub/Linux/distributions/archlinux/stable +#Server = ftp://ftp2.archlinux.org/stable +#Server = ftp://ftp3.archlinux.org/stable -# Sync_Server = ftp.oit.unc.edu -# Sync_Tree_Path = /pub/Linux/distributions/archlinux/current +# This is a typical setup for a local package repository. To have pacman +# resolve dependencies and install your custom packages with the --sync +# operation, you must generate a sync db from your custom PKGBUILDs and +# place it in the directory specified by the Server directive. +# +# # gensync /usr/abs/local /home/custompkgs/custom.db.tar.gz +# +# The sync database must be of the form {treename}.db.gz, where treename +# is the name of the package tree (in this case, 'custom'). +# +# Then you can activate this custom repository by uncommenting the last +# two lines and using pacman as usual: +# +# # pacman -S --refresh +# :: Synchronizing package databases... +# current.db.tar.gz [#################################] 100% | 20K +# custom.db.tar.gz [/home/custompkgs/ ] 100% | LOCAL +# +# # pacman -S my_custom_pkg +# +# Targets: my_custom_pkg-0.12-1 +# +# Do you want to install/upgrade these packages? [Y/n] +# +# :: Retrieving packages from custom... +# my_custom_pkg-0.12-1.pkg [/home/custompkgs/ ] 100% | LOCAL +# +# checking for conflicts... done. +# installing my_custom_pkg... done. +# +#[custom] +#Server = local:///home/custompkgs diff --git a/etc/supfile b/etc/supfile deleted file mode 100644 index 274b0e46..00000000 --- a/etc/supfile +++ /dev/null @@ -1,23 +0,0 @@ -# -# /etc/abs/supfile -# - -# this is the host containing the master ABS files -*default host=archlinux.org - -*default base=/usr/abs -*default prefix=/usr/abs -*default release=cvs -*default delete -*default use-rel-suffix -*default compress - -# -# Set tag equal to the package tree you wish to follow. CURRENT and -# STABLE are the most commonly used, but you can specify specific -# versions or tag names. Examples are RELEASE_0_2, VEGA, RELEASE_0_3, -# FIREFLY, etc. -# -*default tag=CURRENT - -abs diff --git a/etc/supfile.arch b/etc/supfile.arch new file mode 100644 index 00000000..5fe3f4b9 --- /dev/null +++ b/etc/supfile.arch @@ -0,0 +1,23 @@ +# +# /etc/abs/supfile +# + +# this is the host containing the master ABS files +*default host=cvs.archlinux.org + +*default base=/usr/abs +*default prefix=/usr/abs +*default release=cvs +*default delete +*default use-rel-suffix +*default compress + +# +# Set tag equal to the package tree you wish to follow. CURRENT and +# STABLE are the most commonly used, but you can specify specific +# versions or tag names. Examples are RELEASE_0_2, VEGA, RELEASE_0_3, +# FIREFLY, etc. +# +*default tag=CURRENT + +arch diff --git a/etc/supfile.unofficial b/etc/supfile.unofficial new file mode 100644 index 00000000..2ed2ef0c --- /dev/null +++ b/etc/supfile.unofficial @@ -0,0 +1,16 @@ +# +# /etc/abs/supfile.unofficial +# + +# this is the host containing the unofficial PKGBUILD files +*default host=unofficial.archlinux.org + +*default base=/usr/abs +*default prefix=/usr/abs +*default release=cvs +*default delete +*default use-rel-suffix +*default compress + +*default tag=CURRENT +unofficial diff --git a/scripts/abs b/scripts/abs index a21bcb68..10e9b9c4 100755 --- a/scripts/abs +++ b/scripts/abs @@ -1,6 +1,6 @@ #!/bin/bash -myver='2.0' +myver='2.1' ABS_ROOT=/usr/abs usage() { @@ -9,7 +9,7 @@ usage() { echo echo "abs will synchronize PKGBUILD scripts from the CVS repository" echo "into /usr/abs. You can follow different package trees by editing" - echo "/etc/abs/supfile" + echo "/etc/abs/supfile.arch" echo exit 0 } @@ -25,17 +25,14 @@ update() { exit 1 fi - if [ ! -r /etc/abs/supfile ]; then - echo "abs: missing config file /etc/abs/supfile" - exit 1 - fi - if [ "`id -u`" != "0" ]; then echo "abs: you must be root to update your ABS tree" exit 1 fi - cd $ABS_ROOT && cvsup -L 1 -r 0 -g -c .sup /etc/abs/supfile + for sup in `find /etc/abs -name "supfile.*"`; do + cd $ABS_ROOT && cvsup -L 1 -r 0 -g -c .sup $sup + done } for opt in "$@"; do diff --git a/scripts/gensync b/scripts/gensync new file mode 100755 index 00000000..4b0f882d --- /dev/null +++ b/scripts/gensync @@ -0,0 +1,104 @@ +#!/bin/bash + +myver='2.1' + +usage() { + echo "gensync $myver" + echo "usage: $0 " + echo + echo "gensync will generate a sync database by reading all PKGBUILD files" + echo "from . gensync builds the database in /tmp/.gensync and then" + echo "compresses it to ." + echo + echo "note: The name is important. It must be of the form" + echo " {treename}.db.tar.gz where {treename} is the name of the custom" + echo " package repository you configured in /etc/pacman.conf. The" + echo " generated database must reside in the same directory as your" + echo " custom packages (also configured in /etc/pacman.conf)" + echo + echo "example: gensync /usr/abs/local /home/mypkgs/custom.db.tar.gz" + echo + echo + exit 0 +} + +db_write_entry() +{ + unset pkgname pkgver pkgrel + unset depends conflicts + source $1 || return 1 + cd /tmp/.gensync + mkdir $pkgname-$pkgver-$pkgrel + cd $pkgname-$pkgver-$pkgrel + # desc + echo "%NAME%" >desc + echo "$pkgname" >>desc + echo "" >>desc + echo "%VERSION%" >>desc + echo "$pkgver-$pkgrel" >>desc + echo "" >>desc + echo "%DESC%" >>desc + echo "$pkgdesc" >>desc + echo "" >>desc + # 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 +} + +if [ $# -lt 2 ]; then + usage + exit 0 +fi + +if [ "$1" = "-h" -o "$1" = "--help" ]; then + usage + exit 0 +fi + +d=`dirname $1` +rootdir=`cd $d && pwd` +rootdir="$rootdir/`basename $1`" +d=`dirname $2` +destfile=`cd $d && pwd` +destfile="$destfile/`basename $2`" + +rm -rf /tmp/.gensync || exit 1 +mkdir -p /tmp/.gensync || exit 1 + +if [ ! -d $rootdir ]; then + echo "gensync: invalid root dir: $rootdir" >&2 + rm -rf /tmp/.gensync + exit 1 +fi + +echo "gensync: building database entries..." >&2 +#for category in `find $rootdir/* -type d -maxdepth 0`; do +for file in `find $rootdir/* -name PKGBUILD`; do + db_write_entry $file + if [ $? -gt 0 ]; then + echo "gensync: error writing entry for $file" >&2 + rm -rf /tmp/.gensync + exit 1 + fi +done + +echo "gensync: compressing to $destfile..." >&2 +cd /tmp/.gensync +tar c * | gzip -9 >$destfile +if [ $? -gt 0 ]; then + echo "gensync: error writing to $destfile" >&2 + rm -rf /tmp/.gensync + exit 1 +fi + +rm -rf /tmp/.gensync + +exit 0 diff --git a/scripts/makepkg b/scripts/makepkg index 2774084f..35e7dac9 100755 --- a/scripts/makepkg +++ b/scripts/makepkg @@ -1,6 +1,6 @@ #!/bin/bash -myver='2.0' +myver='2.1' startdir=`pwd` [ -f /etc/makepkg.conf ] && source /etc/makepkg.conf @@ -30,21 +30,26 @@ fi CLEANUP=0 INSTALL=0 +BUILDSCRIPT="./PKGBUILD" -if [ "$1" = "-c" -o "$1" = "--clean" ]; then - shift - CLEANUP=1 -fi -if [ "$1" = "-i" -o "$1" = "--install" ]; then - shift - INSTALL=1 -fi +for arg in $*; do + case $arg in + -c|--clean) + CLEANUP=1 + ;; + -i|--install) + INSTALL=1 + ;; + *) + BUILDSCRIPT=$arg + ;; + esac +done unset pkgname pkgver pkgrel pkgdesc unset depends conflicts backup source install build umask 0022 - # check for a download utility if [ -x /usr/bin/wget ]; then ftpagent="/usr/bin/wget --passive-ftp --tries=3 --waitretry=3" @@ -57,11 +62,6 @@ else exit 1 fi -BUILDSCRIPT="./PKGBUILD" -if [ "$1" != "" ]; then - BUILDSCRIPT=$1 -fi - if [ ! -f $BUILDSCRIPT ]; then msg "==> ERROR: $BUILDSCRIPT does not exist." exit 1 @@ -71,40 +71,40 @@ source $BUILDSCRIPT # check for no-no's if [ `echo $pkgver | grep '-'` ]; then - msg "==> ERROR: pkgver is not allowed to contain hyphens." - exit 1 + msg "==> ERROR: pkgver is not allowed to contain hyphens." + exit 1 fi if [ `echo $pkgrel | grep '-'` ]; then - msg "==> ERROR: pkgrel is not allowed to contain hyphens." - exit 1 + msg "==> ERROR: pkgrel is not allowed to contain hyphens." + exit 1 fi if [ `type -p pacman` ]; then - msg "==> Checking Dependencies..." - missdep=`pacman -T ${depends[@]}` - ret=$? - if [ "$ret" != "0" ]; then - if [ "$ret" = "127" ]; then - msg "==> ERROR: Dependency Check Failed:" - msg "" - nl=0 - for dep in $missdep; do - echo -ne "$dep " >&2 - if [ "$nl" = "1" ]; then - nl=0 - echo -ne "\n" >&2 - continue - fi - nl=1 - done - msg "" - else - msg "==> ERROR: pacman returned a fatal error." - fi - exit 1 - fi + msg "==> Checking Dependencies..." + missdep=`pacman -T ${depends[@]}` + ret=$? + if [ "$ret" != "0" ]; then + if [ "$ret" = "127" ]; then + msg "==> ERROR: Dependency Check Failed:" + msg "" + nl=0 + for dep in $missdep; do + echo -ne "$dep " >&2 + if [ "$nl" = "1" ]; then + nl=0 + echo -ne "\n" >&2 + continue + fi + nl=1 + done + msg "" + else + msg "==> ERROR: pacman returned a fatal error." + fi + exit 1 + fi else - msg "==> WARNING: pacman was not found in PATH. skipping dependency checks." + msg "==> WARNING: pacman was not found in PATH. skipping dependency checks." fi d=`date` @@ -143,21 +143,21 @@ for netfile in ${source[@]}; do cmd="tar --use-compress-program=gzip -xf $file" ;; *.tar.bz2) cmd="tar --use-compress-program=bzip2 -xf $file" ;; - *.tar) - cmd="tar -xf $file" ;; + *.tar) + cmd="tar -xf $file" ;; *.zip) cmd="unzip -qq $file" ;; - *) - cmd="cp ../$file ." ;; - esac - msg "==> $cmd" - $cmd + *.gz) + cmd="gunzip $file" ;; + esac + msg "==> $cmd" + $cmd done # check for existing pkg directory if [ -d $startdir/pkg ]; then - msg "==> Removing existing pkg directory..." - rm -rf $startdir/pkg + msg "==> Removing existing pkg directory..." + rm -rf $startdir/pkg fi mkdir -p $startdir/pkg @@ -172,9 +172,9 @@ fi # get some package meta info builddate=`date -u "+%a %b %d %k:%M:%S %Y"` if [ "$PACKAGER" != "" ]; then - packager="$PACKAGER" + packager="$PACKAGER" else - packager="Arch Linux (http://www.archlinux.org)" + packager="Arch Linux (http://www.archlinux.org)" fi size=`du -cb $startdir/pkg | tail -1 | awk '{print $1}'` @@ -203,8 +203,8 @@ done # check for an install script if [ "$install" != "" ]; then - msg "==> Copying install script..." - cp $startdir/$install $startdir/pkg/._install + msg "==> Copying install script..." + cp $startdir/$install $startdir/pkg/._install fi # remove info/doc files @@ -214,9 +214,9 @@ rm -rf pkg/usr/doc pkg/usr/share/doc # move /usr/share/man files to /usr/man if [ -d pkg/usr/share/man ]; then - mkdir -p pkg/usr/man - cp -a pkg/usr/share/man/* pkg/usr/man/ - rm -rf pkg/usr/share/man + mkdir -p pkg/usr/man + cp -a pkg/usr/share/man/* pkg/usr/man/ + rm -rf pkg/usr/share/man fi # strip binaries @@ -230,23 +230,23 @@ find pkg/{,usr,usr/local}/{bin,sbin} -type f -exec /usr/bin/strip '{}' ';' 2>&1 msg "==> Compressing package..." cd $startdir/pkg if [ -f $startdir/pkg/._install ]; then - tar czvf $startdir/$pkgname-$pkgver-$pkgrel.pkg.tar.gz .PKGINFO ._install * >../filelist + tar czvf $startdir/$pkgname-$pkgver-$pkgrel.pkg.tar.gz .PKGINFO ._install * >../filelist else - tar czvf $startdir/$pkgname-$pkgver-$pkgrel.pkg.tar.gz .PKGINFO * >../filelist + tar czvf $startdir/$pkgname-$pkgver-$pkgrel.pkg.tar.gz .PKGINFO * >../filelist fi cd $startdir if [ "$CLEANUP" = "1" ]; then - msg "==> Cleaning up" - rm -rf src pkg + msg "==> Cleaning up" + rm -rf src pkg fi d=`date` msg "==> Finished making $pkgname ($d)" if [ "$INSTALL" = "1" ]; then - msg "==> Running pacman --upgrade" - pacman --upgrade $pkgname-$pkgver-$pkgrel.pkg.tar.gz + msg "==> Running pacman --upgrade" + pacman --upgrade $pkgname-$pkgver-$pkgrel.pkg.tar.gz fi exit 0 diff --git a/scripts/makeworld b/scripts/makeworld index 8b3ec177..448dbc49 100755 --- a/scripts/makeworld +++ b/scripts/makeworld @@ -1,35 +1,52 @@ #!/bin/bash toplevel=`pwd` -version="2.0" +version="2.1" -if [ $# -lt 2 -o "$1" = "--help" -o "$1" = "-h" ]; then - echo "makeworld version $version" +usage() { + echo "makeworld version $version" echo "usage: $0 [options] [category] ..." - echo "options:" - echo " -c, --clean Clean up work files after build" - echo " -i, --install Install package after successful build" - echo " -h, --help This help" - echo - echo " where is one or more of base, opt, contrib" - echo " eg: makeworld /packages base opt" + echo "options:" + echo " -c, --clean Clean up work files after build" + echo " -i, --install Install package after successful build" + echo " -h, --help This help" + echo + echo " where 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 fi MAKEPKG_OPTS= -if [ "$1" = "-c" -o "$1" = "--clean" ]; then - shift - MAKEPKG_OPTS="$MAKEPKG_OPTS -c" -fi -if [ "$1" = "-i" -o "$1" = "--install" ]; then - shift - MAKEPKG_OPTS="$MAKEPKG_OPTS -i" -fi +for arg in $*; do + case $arg in + -c|--clean) + MAKEPKG_OPTS="$MAKEPKG_OPTS -c" + ;; + -i|--install) + MAKEPKG_OPTS="$MAKEPKG_OPTS -i" + ;; + *) + dest=$arg + shift + break + ;; + esac + shift + if [ "$dest" != "" ]; then + break; + fi +done -dest=$1 -shift +if [ "$dest" = "" ]; then + usage + exit 1 +fi sd=`date +"[%b %d %H:%M]"` diff --git a/scripts/pacsync b/scripts/pacsync index 7537f284..dd9a9ef9 100755 --- a/scripts/pacsync +++ b/scripts/pacsync @@ -1,6 +1,6 @@ #!/bin/sh echo -echo "Pacman 2.0 no longer comes with pacsync. Use 'pacman -S' instead." +echo "Pacman 2.0+ no longer comes with pacsync. Use 'pacman -S' instead." echo " (see 'pacman -S --help' or the manpage for syntax)" echo diff --git a/src/db.c b/src/db.c index f747be5b..b2489bb1 100644 --- a/src/db.c +++ b/src/db.c @@ -31,6 +31,7 @@ #include "package.h" #include "db.h" #include "util.h" +#include "pacsync.h" #include "pacman.h" extern PMList *pm_packages; diff --git a/src/list.c b/src/list.c index 2a33b6e3..717aab2b 100644 --- a/src/list.c +++ b/src/list.c @@ -93,6 +93,18 @@ int list_count(PMList *list) return(i); } +int list_isin(PMList *haystack, void *needle) +{ + PMList *lp; + + for(lp = haystack; lp; lp = lp->next) { + if(lp->data == needle) { + return(1); + } + } + return(0); +} + /* List one is extended and returned * List two is freed (but not its data) */ diff --git a/src/list.h b/src/list.h index 9749d934..68ff5651 100644 --- a/src/list.h +++ b/src/list.h @@ -12,6 +12,7 @@ PMList* list_new(); void list_free(PMList* list); PMList* list_add(PMList* list, void* data); int list_count(PMList* list); +int list_isin(PMList *haystack, void *needle); PMList* list_merge(PMList *one, PMList *two); PMList* list_last(PMList* list); diff --git a/src/package.c b/src/package.c index 69461f67..95913b14 100644 --- a/src/package.c +++ b/src/package.c @@ -30,6 +30,7 @@ #include "package.h" #include "db.h" #include "util.h" +#include "pacsync.h" #include "pacman.h" extern tartype_t gztype; diff --git a/src/pacman.c b/src/pacman.c index 7c70cacd..053c5081 100644 --- a/src/pacman.c +++ b/src/pacman.c @@ -72,25 +72,24 @@ unsigned short pmo_s_upgrade = 0; unsigned short pmo_s_sync = 0; unsigned short pmo_s_search = 0; unsigned short pmo_s_clean = 0; +PMList *pmo_noupgrade = NULL; -/* configuration options */ -char pmc_syncserver[512] = ""; -char pmc_syncpath[512] = ""; -char pmc_syncname[512] = ""; - -char *lckfile = "/tmp/pacman.lck"; +/* list of sync_t structs for sync locations */ +PMList *pmc_syncs = NULL; /* list of installed packages */ PMList *pm_packages = NULL; - /* list of targets specified on command line */ -PMList *pm_targets = NULL; +PMList *pm_targets = NULL; + +char *lckfile = "/tmp/pacman.lck"; int main(int argc, char *argv[]) { int ret = 0; char *ptr = NULL; char *dbpath = NULL; + char path[PATH_MAX]; pacdb_t *db_local = NULL; PMList *lp; @@ -141,6 +140,12 @@ int main(int argc, char *argv[]) signal(SIGINT, cleanup); signal(SIGTERM, cleanup); + /* parse the system-wide config file */ + snprintf(path, PATH_MAX, "/%s", PACCONF); + if(parseconfig(path)) { + cleanup(1); + } + /* check for db existence */ /* add a trailing '/' if there isn't one */ if(pmo_root[strlen(pmo_root)-1] != '/') { @@ -249,37 +254,18 @@ int pacman_deptest(pacdb_t *db, PMList *targets) int pacman_sync(pacdb_t *db, PMList *targets) { - char url[1024]; - char *dbpath = NULL; + char dbpath[PATH_MAX]; int allgood = 1, confirm = 0; - pacdb_t *db_sync = NULL; - PMList *pkgcache = NULL; - PMList *i, *j; + int cols; + PMList *i, *j, *k; PMList *final = NULL; PMList *trail = NULL; - PMList *deps = NULL; - int cols; + PMList *databases = NULL; - /* parse the system-wide config file */ - snprintf(url, 511, "/%s", PACCONF); - if(parseconfig(url)) { + if(!list_count(pmc_syncs)) { + fprintf(stderr, "error: no usable package repositories configured.\n"); return(1); } - if(!strlen(pmc_syncserver)) { - fprintf(stderr, "error: no Sync_Server specified in %s\n", url); - return(1); - } - if(!strlen(pmc_syncname)) { - fprintf(stderr, "error: no Sync_Tree_Name specified in %s\n", url); - return(1); - } - if(!strlen(pmc_syncpath)) { - fprintf(stderr, "error: no Sync_Tree_Path specified in %s\n", url); - return(1); - } - if(pmc_syncpath[0] != '/') { - sprintf(pmc_syncpath, "/%s", pmc_syncpath); - } if(pmo_s_clean) { mode_t oldmask; @@ -303,54 +289,61 @@ int pacman_sync(pacdb_t *db, PMList *targets) if(pmo_s_sync && !pmo_s_search) { /* grab a fresh package list */ - printf(":: Synchronizing remote package tree... \n"); + printf(":: Synchronizing package databases... \n"); sync_synctree(); - printf("\n"); - } - - /* open the sync db */ - MALLOC(dbpath, PATH_MAX); - snprintf(dbpath, PATH_MAX-1, "%s%s", pmo_root, PKGDIR); - db_sync = db_open(dbpath, pmc_syncname); - if(db_sync == NULL) { - fprintf(stderr, "error: could not open the sync database.\n"); - fprintf(stderr, " have you used --refresh yet?\n"); - return(1); } - /* cache packages */ - pkgcache = db_loadpkgs(db_sync, pkgcache); - if(db_sync == NULL) { - fprintf(stderr, "error: could not open sync database (%s/%s)\n", dbpath, pmc_syncname); - return(1); + /* open the database(s) */ + for(i = pmc_syncs; i; i = i->next) { + pacdb_t *db_sync = NULL; + dbsync_t *dbs = NULL; + sync_t *sync = (sync_t*)i->data; + + snprintf(dbpath, PATH_MAX, "%s%s", pmo_root, PKGDIR); + db_sync = db_open(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"); + return(1); + } + MALLOC(dbs, sizeof(dbsync_t)); + dbs->sync = sync; + dbs->db = db_sync; + /* cache packages */ + dbs->pkgcache = NULL; + dbs->pkgcache = db_loadpkgs(db_sync, dbs->pkgcache); + databases = list_add(databases, dbs); } final = list_new(); trail = list_new(); if(pmo_s_search) { - /* search sync db */ + /* search sync databases */ for(i = targets; i; i = i->next) { char *targ = strdup(i->data); strtoupper(targ); - for(j = pkgcache; j; j = j->next) { - pkginfo_t *pkg = (pkginfo_t*)j->data; - char *haystack; - /* check name */ - haystack = strdup(pkg->name); - strtoupper(haystack); - if(strstr(haystack, targ)) { - printf("%s %s\n", pkg->name, pkg->version); - } else { - /* check description */ - FREE(haystack); - haystack = strdup(pkg->desc); + 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\n", pkg->name, pkg->version); + } else { + /* check description */ + FREE(haystack); + haystack = strdup(pkg->desc); + strtoupper(haystack); + if(strstr(haystack, targ)) { + printf("%s %s\n", pkg->name, pkg->version); + } } + FREE(haystack); } - FREE(haystack); } FREE(targ); } @@ -359,18 +352,18 @@ int pacman_sync(pacdb_t *db, PMList *targets) for(i = pm_packages; i && allgood; i = i->next) { int cmp, found = 0; pkginfo_t *local = (pkginfo_t*)i->data; - pkginfo_t *sync = NULL; - - for(j = pkgcache; !found && j; j = j->next) { - sync = (pkginfo_t*)j->data; - if(local == NULL || local->name == NULL) { - vprint("local is NULL!\n"); - } - if(sync == NULL || sync->name == NULL) { - vprint("sync is NULL!\n"); - } - if(!strcmp(local->name, sync->name)) { - found = 1; + syncpkg_t *sync = NULL; + MALLOC(sync, sizeof(syncpkg_t)); + + 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(local->name, pkg->name)) { + found = 1; + sync->pkg = pkg; + sync->dbs = dbs; + } } } if(!found) { @@ -378,7 +371,7 @@ int pacman_sync(pacdb_t *db, PMList *targets) continue; } /* compare versions and see if we need to upgrade */ - cmp = rpmvercmp(local->version, sync->version); + cmp = rpmvercmp(local->version, sync->pkg->version); if(cmp > 0) { /* local version is newer */ fprintf(stderr, ":: %s-%s: local version is newer\n", @@ -390,12 +383,12 @@ int pacman_sync(pacdb_t *db, PMList *targets) continue; } else { /* re-fetch the package record with dependency info */ - sync = db_scan(db_sync, sync->name, INFRQ_DESC | INFRQ_DEPENDS); + sync->pkg = db_scan(sync->dbs->db, sync->pkg->name, INFRQ_DESC | INFRQ_DEPENDS); /* add to the targets list */ - if(!is_pkgin(sync, final)) { - allgood = !resolvedeps(db, db_sync, sync, final, trail); + if(!list_isin(final, sync)) { + allgood = !resolvedeps(db, databases, sync, final, trail); /* check again, as resolvedeps could have added our target for us */ - if(!is_pkgin(sync, final)) { + if(!list_isin(final, sync)) { final = list_add(final, sync); } } @@ -408,19 +401,35 @@ int pacman_sync(pacdb_t *db, PMList *targets) /* process targets */ for(i = targets; i && allgood; i = i->next) { if(i->data) { - int cmp; + int cmp, found = 0; pkginfo_t *local; - pkginfo_t *sync; + syncpkg_t *sync = NULL; + MALLOC(sync, sizeof(syncpkg_t)); local = db_scan(db, (char*)i->data, INFRQ_DESC); - sync = db_scan(db_sync, (char*)i->data, INFRQ_DESC | INFRQ_DEPENDS); - if(sync == NULL) { - fprintf(stderr, ":: %s: not found in sync db\n", (char*)i->data); + //sync = db_scan(db_sync, (char*)i->data, INFRQ_DESC | INFRQ_DEPENDS); + 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)) { + found = 1; + sync->dbs = dbs; + /* re-fetch the package record with dependency info */ + sync->pkg = db_scan(sync->dbs->db, pkg->name, INFRQ_DESC | INFRQ_DEPENDS); + if(sync->pkg == NULL) { + found = 0; + } + } + } + } + if(!found) { + fprintf(stderr, "%s: not found in sync db\n", (char*)i->data); continue; } if(local) { /* this is an upgrade, compare versions and determine if it is necessary */ - cmp = rpmvercmp(local->version, sync->version); + cmp = rpmvercmp(local->version, sync->pkg->version); if(cmp > 0) { /* local version is newer - get confirmation first */ if(!yesno(":: %s-%s: local version is newer. Upgrade anyway? [Y/n] ", local->name, local->version)) { @@ -434,10 +443,24 @@ int pacman_sync(pacdb_t *db, PMList *targets) } } /* add to targets list */ - if(!is_pkgin(sync, final)) { - allgood = !resolvedeps(db, db_sync, sync, final, trail); + found = 0; + for(j = final; j; j = j->next) { + syncpkg_t *tmp = (syncpkg_t*)j->data; + if(tmp && !strcmp(tmp->pkg->name, sync->pkg->name)) { + found = 1; + } + } + if(!found) { + allgood = !resolvedeps(db, databases, sync, final, trail); /* check again, as resolvedeps could have added our target for us */ - if(!is_pkgin(sync, final)) { + found = 0; + for(j = final; j; j = j->next) { + syncpkg_t *tmp = (syncpkg_t*)j->data; + if(tmp && !strcmp(tmp->pkg->name, sync->pkg->name)) { + found = 1; + } + } + if(!found) { final = list_add(final, sync); } } @@ -447,7 +470,16 @@ int pacman_sync(pacdb_t *db, PMList *targets) if(allgood) { /* check for inter-conflicts and whatnot */ - deps = checkdeps(db, PM_UPGRADE, final); + 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); + } + } + deps = checkdeps(db, PM_UPGRADE, list); if(deps) { fprintf(stderr, "error: unresolvable conflicts/dependencies:\n"); for(i = deps; i; i = i->next) { @@ -474,6 +506,12 @@ int pacman_sync(pacdb_t *db, PMList *targets) /* abort mission */ allgood = 0; } + /* cleanup */ + for(i = list; i; i = i->next) { + i->data = NULL; + } + list_free(list); + list = NULL; /* list targets */ if(final && final->data) { @@ -481,18 +519,18 @@ int pacman_sync(pacdb_t *db, PMList *targets) } cols = 9; for(i = final; allgood && i; i = i->next) { - pkginfo_t *p = (pkginfo_t*)i->data; - if(p) { + syncpkg_t *s = (syncpkg_t*)i->data; + if(s && s->pkg) { char t[PATH_MAX]; - int s; - snprintf(t, PATH_MAX, "%s-%s ", p->name, p->version); - s = strlen(t); - if(s+cols > 78) { + 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", " "); } fprintf(stderr, "%s", t); - cols += s; + cols += len; } } printf("\n"); @@ -504,66 +542,96 @@ int pacman_sync(pacdb_t *db, PMList *targets) } } - if(allgood && confirm) { - PMList *files = NULL; + if(allgood && confirm && final && final->data) { char ldir[PATH_MAX]; int varcache = 1; + int done = 0; + int count = 0; + sync_t *current = NULL; + PMList *processed = NULL; + PMList *files = NULL; - /* download targets */ - for(i = final; i; i = i->next) { - pkginfo_t *p = (pkginfo_t*)i->data; - if(p) { - struct stat buf; - char path[PATH_MAX]; - - snprintf(path, PATH_MAX, "%svar/cache/pacman/pkg/%s-%s.pkg.tar.gz", - pmo_root, p->name, p->version); - if(stat(path, &buf)) { - /* file is not in the cache dir, so add it to the list */ - snprintf(path, PATH_MAX, "%s-%s.pkg.tar.gz", p->name, p->version); - files = list_add(files, strdup(path)); - } + /* group sync records by repository and download */ + while(!done) { + if(current) { + processed = list_add(processed, current); + current = NULL; } - } - snprintf(ldir, PATH_MAX, "%svar/cache/pacman/pkg", pmo_root); + for(i = final; i; i = i->next) { + syncpkg_t *sync = (syncpkg_t*)i->data; + if(current == NULL) { + /* we're starting on a new repository */ + if(!list_isin(processed, sync->dbs->sync)) { + current = sync->dbs->sync; + } + } + if(current && !strcmp(current->treename, sync->dbs->sync->treename)) { + struct stat buf; + char path[PATH_MAX]; - if(files) { - struct stat buf; - - printf("\n:: Downloading packages...\n"); fflush(stdout); - if(stat(ldir, &buf)) { - mode_t oldmask; - char parent[PATH_MAX]; - - /* 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); - oldmask = umask(0000); - if(mkdir(parent, 0755) || 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"); - snprintf(ldir, PATH_MAX, "/tmp"); - varcache = 0; + snprintf(path, PATH_MAX, "%svar/cache/pacman/pkg/%s-%s.pkg.tar.gz", + pmo_root, sync->pkg->name, sync->pkg->version); + if(stat(path, &buf)) { + /* file is not in the cache dir, so add it to the list */ + snprintf(path, PATH_MAX, "%s-%s.pkg.tar.gz", sync->pkg->name, sync->pkg->version); + files = list_add(files, strdup(path)); + } else { + count++; + } } - umask(oldmask); } - if(downloadfiles(pmc_syncserver, pmc_syncpath, ldir, files)) { - fprintf(stderr, "error: ftp transfer failed.\n"); - allgood = 0; + snprintf(ldir, PATH_MAX, "%svar/cache/pacman/pkg", pmo_root); + + if(files) { + struct stat buf; + + printf("\n:: Retrieving packages from %s...\n", current->treename); + fflush(stdout); + if(stat(ldir, &buf)) { + mode_t oldmask; + char parent[PATH_MAX]; + + /* 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); + 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"); + 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); + allgood = 0; + } + count += list_count(files); + list_free(files); + files = NULL; } + if(count == list_count(final)) { + done = 1; + } + } + printf("\n"); + + /* double-check */ + if(files) { list_free(files); files = NULL; } - /* install targets */ for(i = final; allgood && i; i = i->next) { char *str; - pkginfo_t *p = (pkginfo_t*)i->data; - if(p) { + syncpkg_t *sync = (syncpkg_t*)i->data; + if(sync->pkg) { MALLOC(str, PATH_MAX); - snprintf(str, PATH_MAX, "%s/%s-%s.pkg.tar.gz", ldir, p->name, p->version); + snprintf(str, PATH_MAX, "%s/%s-%s.pkg.tar.gz", ldir, sync->pkg->name, sync->pkg->version); files = list_add(files, str); } } @@ -580,22 +648,26 @@ int pacman_sync(pacdb_t *db, PMList *targets) } /* cleanup */ - for(i = pkgcache; i; i = i->next) { - if(i->data) freepkg((pkginfo_t*)i->data); - i->data = NULL; - } for(i = final; i; i = i->next) { - if(i->data) freepkg((pkginfo_t*)i->data); + syncpkg_t *sync = (syncpkg_t*)i->data; + if(sync) freepkg(sync->pkg); + free(sync); i->data = NULL; } for(i = trail; i; i = i->next) { /* this list used the same pointers as final, so they're already freed */ i->data = NULL; } - list_free(pkgcache); + for(i = databases; i; i = i->next) { + dbsync_t *dbs = (dbsync_t*)i->data; + db_close(dbs->db); + list_free(dbs->pkgcache); + free(dbs); + i->data = NULL; + } + list_free(databases); list_free(final); list_free(trail); - db_close(db_sync); return(!allgood); } @@ -726,6 +798,7 @@ int pacman_add(pacdb_t *db, PMList *targets) vprint("extracting files...\n"); for(i = 0; !th_read(tar); i++) { int nb = 0; + int notouch = 0; char *md5_orig = NULL; char pathname[PATH_MAX]; strncpy(pathname, th_get_pathname(tar), PATH_MAX); @@ -746,13 +819,17 @@ int pacman_add(pacdb_t *db, PMList *targets) if(!stat(expath, &buf) && !S_ISDIR(buf.st_mode)) { /* file already exists */ - if(!pmo_upgrade) { - nb = is_in(pathname, info->backup); + if(is_in(pathname, pmo_noupgrade)) { + notouch = 1; } else { - /* op == PM_UPGRADE */ - md5_orig = needbackup(pathname, oldpkg->backup); - if(md5_orig) { - nb = 1; + if(!pmo_upgrade) { + nb = is_in(pathname, info->backup); + } else { + /* op == PM_UPGRADE */ + md5_orig = needbackup(pathname, oldpkg->backup); + if(md5_orig) { + nb = 1; + } } } } @@ -857,7 +934,14 @@ int pacman_add(pacdb_t *db, PMList *targets) unlink(temp); FREE(temp); } else { - /*vprint(" %s\n", expath);*/ + if(!notouch) { + /*vprint(" %s\n", expath);*/ + } 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); + /*tar_skip_regfile(tar);*/ + } if(tar_extract_file(tar, expath)) { fprintf(stderr, "could not extract %s: %s\n", pathname, strerror(errno)); errors++; @@ -1026,6 +1110,12 @@ int pacman_remove(pacdb_t *db, PMList *targets) if(needbackup((char*)lp->data, info->backup)) { nb = 1; } + if(!nb && pmo_upgrade) { + /* check pmo_noupgrade */ + if(is_in((char*)lp->data, pmo_noupgrade)) { + nb = 1; + } + } snprintf(line, PATH_MAX, "%s%s", pmo_root, (char*)lp->data); if(lstat(line, &buf)) { vprint("file %s does not exist\n", line); @@ -1312,31 +1402,53 @@ int pacman_upgrade(pacdb_t *db, PMList *targets) } /* populates *list with packages that need to be installed to satisfy all - * dependencies (recursive) for *package + * dependencies (recursive) for *syncpkg->pkg * * make sure *list and *trail are already initialized */ -int resolvedeps(pacdb_t *local, pacdb_t *sync, pkginfo_t *package, PMList *list, PMList *trail) +int resolvedeps(pacdb_t *local, PMList *databases, syncpkg_t *syncpkg, PMList *list, PMList *trail) { - pkginfo_t *info; - PMList *i; + PMList *i, *j, *k; PMList *targ = NULL; PMList *deps = NULL; targ = list_new(); - targ = list_add(targ, package); + targ = list_add(targ, syncpkg->pkg); deps = checkdeps(local, PM_ADD, targ); targ->data = NULL; list_free(targ); for(i = deps; i; i = i->next) { + int found = 0; + syncpkg_t *sync = NULL; depmissing_t *miss = (depmissing_t*)i->data; - info = db_scan(sync, miss->depend.name, INFRQ_DESC | INFRQ_DEPENDS); - if(info == NULL) { + MALLOC(sync, sizeof(syncpkg_t)); + + /* find the package in one of the repositories */ + 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(miss->depend.name, pkg->name)) { + found = 1; + /* re-fetch the package record with dependency info */ + sync->pkg = db_scan(dbs->db, pkg->name, INFRQ_DESC | INFRQ_DEPENDS); + sync->dbs = dbs; + } + } + } + if(!found) { fprintf(stderr, "error: cannot resolve dependencies for \"%s\":\n", miss->target); fprintf(stderr, " \"%s\" is not in the package set\n", miss->depend.name); return(1); } - if(is_pkgin(info, list) == 1) { + found = 0; + for(j = list; j; j = j->next) { + syncpkg_t *tmp = (syncpkg_t*)j->data; + if(tmp && !strcmp(tmp->pkg->name, sync->pkg->name)) { + found = 1; + } + } + if(found) { /* this dep is already in the target list */ continue; } @@ -1344,13 +1456,21 @@ int resolvedeps(pacdb_t *local, pacdb_t *sync, pkginfo_t *package, PMList *list, fprintf(stderr, "error: %s conflicts with %s\n", miss->target, miss->depend.name); return(1); } else if(miss->type == DEPEND) { - /*printf("resolving %s\n", info->name); fflush(stdout);*/ - if(!is_pkgin(info, trail)) { - list_add(trail, info); - if(resolvedeps(local, sync, info, list, trail)) { + /*printf("resolving %s\n", sync->pkg->name); fflush(stdout);*/ + found = 0; + for(j = trail; j; j = j->next) { + syncpkg_t *tmp = (syncpkg_t*)j->data; + if(tmp && !strcmp(tmp->pkg->name, sync->pkg->name)) { + found = 1; + } + } + if(!found) { + list_add(trail, sync); + if(resolvedeps(local, databases, sync, list, trail)) { return(1); } - list_add(list, info); + 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);*/ @@ -1398,7 +1518,7 @@ PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets) if((p = db_scan(db, j->data, INFRQ_DESC | INFRQ_DEPENDS)) == NULL) { continue; } - for(k = p->depends; k; k = k->next) { + for(k = p->depends; k && !found; k = k->next) { if(splitdep(k->data, &depend)) { continue; } diff --git a/src/pacman.h b/src/pacman.h index 330969ce..37b86853 100644 --- a/src/pacman.h +++ b/src/pacman.h @@ -22,7 +22,7 @@ #define _PAC_PACMAN_H #ifndef PACVER -#define PACVER "2.0" +#define PACVER "2.1" #endif #ifndef PKGDIR @@ -50,7 +50,7 @@ int pacman_sync(pacdb_t *db, PMList *targets); int pacman_deptest(pacdb_t *db, PMList *targets); PMList* checkdeps(pacdb_t *db, unsigned short op, PMList *targets); -int resolvedeps(pacdb_t *local, pacdb_t *sync, pkginfo_t *package, PMList *list, PMList *trail); +int resolvedeps(pacdb_t *local, PMList *databases, syncpkg_t *sync, PMList *list, PMList *trail); int splitdep(char *depstr, depend_t *depend); int lckmk(char *file, int retries, unsigned int sleep_secs); diff --git a/src/pacsync.c b/src/pacsync.c index 224528f8..a76da444 100644 --- a/src/pacsync.c +++ b/src/pacsync.c @@ -41,125 +41,171 @@ static char sync_fnm[25]; /* pacman options */ extern char *pmo_root; -/* configuration options */ -extern char pmc_syncserver[512]; -extern char pmc_syncpath[512]; -extern char pmc_syncname[512]; + +/* sync servers */ +extern PMList *pmc_syncs; int sync_synctree() { char ldir[PATH_MAX] = ""; char path[PATH_MAX]; mode_t oldmask; - char *str; PMList *files = NULL; - - snprintf(ldir, PATH_MAX, "%s%s/%s", pmo_root, PKGDIR, pmc_syncname); - - /* remove the old dir */ - vprint("Removing %s (if it exists)\n", ldir); - rmrf(ldir); - - /* make the new dir */ - oldmask = umask(0000); - mkdir(ldir, 0755); - umask(oldmask); - - /* build out list of one */ - snprintf(path, PATH_MAX, "%s.db.tar.gz", pmc_syncname); - str = strdup(path); - files = list_add(files, str); - if(downloadfiles(pmc_syncserver, pmc_syncpath, ldir, files)) { + 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); + + /* build a one-element list */ + snprintf(path, PATH_MAX, "%s.db.tar.gz", sync->treename); + files = list_add(files, strdup(path)); + + success = 1; + if(downloadfiles(sync->servers, ldir, files)) { + fprintf(stderr, "failed to synchronize %s\n", sync->treename); + success = 0; + } + /*printf("\n");*/ list_free(files); - return(1); - } - - /* uncompress the sync database */ - snprintf(path, PATH_MAX, "%s/%s", ldir, (char*)files->data); - list_free(files); - vprint("Unpacking %s...\n", path); - if(unpack(path, ldir)) { - return(1); + 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); + /* remove the old dir */ + vprint("removing %s (if it exists)\n", ldir); + rmrf(ldir); + + /* make the new dir */ + oldmask = umask(0000); + mkdir(ldir, 0755); + umask(oldmask); + + /* uncompress the sync database */ + vprint("Unpacking %s...\n", path); + if(unpack(path, ldir)) { + return(1); + } + } + /* remove the .tar.gz */ + unlink(path); } - /* remove the .tar.gz */ - unlink(path); - - return(0); + return(!success); } -int downloadfiles(char *server, char *remotepath, char *localpath, PMList *files) +int downloadfiles(PMList *servers, char *localpath, PMList *files) { int fsz; netbuf *control = NULL; PMList *lp; - int ret = 0; + int done = 0; + PMList *complete = NULL; + PMList *i; if(files == NULL) { return(0); } - FtpInit(); - if(!FtpConnect(server, &control)) { - fprintf(stderr, "error: cannot connect to %s\n", server); - return(1); - } - if(!FtpLogin("anonymous", "arch@guest", control)) { - fprintf(stderr, "error: anonymous login failed\n"); - FtpQuit(control); - return(1); - } - - - if(!FtpChdir(remotepath, control)) { - fprintf(stderr, "error: could not cwd to %s: %s\n", remotepath, - FtpLastResponse(control)); - return(1); - } - - /* get each file in the list */ - for(lp = files; lp; lp = lp->next) { - char output[PATH_MAX]; - int j; - - snprintf(output, PATH_MAX, "%s/%s", localpath, (char*)lp->data); - - /* passive mode */ - /* TODO: make passive ftp an option */ - if(!FtpOptions(FTPLIB_CONNMODE, FTPLIB_PASSIVE, control)) { - fprintf(stderr, "warning: failed to set passive mode\n"); + for(i = servers; i && !done; i = i->next) { + server_t *server = (server_t*)i->data; + + if(!server->islocal) { + FtpInit(); + if(!FtpConnect(server->server, &control)) { + fprintf(stderr, "error: cannot connect to %s\n", server->server); + continue; + } + if(!FtpLogin("anonymous", "arch@guest", control)) { + fprintf(stderr, "error: anonymous login failed\n"); + FtpQuit(control); + continue; + } + if(!FtpChdir(server->path, control)) { + fprintf(stderr, "error: could not cwd to %s: %s\n", server->path, + FtpLastResponse(control)); + continue; + } } - if(!FtpSize((char*)lp->data, &fsz, FTPLIB_IMAGE, control)) { - fprintf(stderr, "warning: failed to get filesize for %s\n", (char*)lp->data); - } - - /* 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); + /* get each file in the list */ + for(lp = files; lp; lp = lp->next) { + char output[PATH_MAX]; + int j; + char *fn = (char*)lp->data; + + if(is_in(fn, complete)) { + continue; + } + + snprintf(output, PATH_MAX, "%s/%s", localpath, fn); + strncpy(sync_fnm, lp->data, 24); + for(j = strlen(sync_fnm); j < 24; j++) { + sync_fnm[j] = ' '; + } + sync_fnm[24] = '\0'; + + if(!server->islocal) { + /* passive mode */ + /* TODO: make passive ftp an option */ + if(!FtpOptions(FTPLIB_CONNMODE, FTPLIB_PASSIVE, control)) { + fprintf(stderr, "warning: failed to set passive mode\n"); + } + if(!FtpSize(fn, &fsz, FTPLIB_IMAGE, control)) { + fprintf(stderr, "warning: failed to get filesize for %s\n", fn); + } + /* 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); - strncpy(sync_fnm, lp->data, 24); - for(j = strlen(sync_fnm); j < 24; j++) { - sync_fnm[j] = ' '; + if(!FtpGet(output, lp->data, FTPLIB_IMAGE, control)) { + fprintf(stderr, "\nfailed downloading %s from %s: %s\n", + fn, server->server, FtpLastResponse(control)); + /* unlink the file */ + unlink(output); + } else { + log_progress(control, fsz, &fsz); + complete = list_add(complete, fn); + } + printf("\n"); + fflush(stdout); + } else { + /* local repository, just copy the file */ + char src[PATH_MAX], dest[PATH_MAX]; + snprintf(src, PATH_MAX, "%s%s", server->path, fn); + snprintf(dest, PATH_MAX, "%s/%s", localpath, fn); + vprint("copying %s to %s\n", src, dest); + if(copyfile(src, dest)) { + fprintf(stderr, "failed copying %s\n", src); + } else { + char out[56]; + printf("%s [", sync_fnm); + strncpy(out, server->path, 33); + printf("%s", out); + for(j = strlen(out); j < 33; j++) { + printf(" "); + } + fputs("] 100% | LOCAL\n", stdout); + fflush(stdout); + + complete = list_add(complete, fn); + } + } + } + if(list_count(complete) == list_count(files)) { + done = 1; } - sync_fnm[24] = '\0'; - if(!FtpGet(output, lp->data, FTPLIB_IMAGE, control)) { - fprintf(stderr, "\nerror: could not download %s: %s\n", (char*)lp->data, - FtpLastResponse(control)); - /* unlink the file */ - unlink(output); - ret = 1; - } else { - log_progress(control, fsz, &fsz); + + if(!server->islocal) { + FtpQuit(control); } - printf("\n"); - fflush(stdout); } - - FtpQuit(control); - return(ret); + + return(!done); } static int log_progress(netbuf *ctl, int xfered, void *arg) diff --git a/src/pacsync.h b/src/pacsync.h index d7c666f3..1838a684 100644 --- a/src/pacsync.h +++ b/src/pacsync.h @@ -21,8 +21,31 @@ #ifndef _PAC_PACSYNC_H #define _PAC_PACSYNC_H +typedef struct __server_t { + unsigned short islocal; + char* server; + char* path; +} server_t; + +typedef struct __sync_t { + char* treename; + PMList *servers; +} sync_t; + +/* linking structs */ +typedef struct __dbsync_t { + pacdb_t *db; + sync_t *sync; + PMList *pkgcache; +} dbsync_t; + +typedef struct __syncpkg_t { + pkginfo_t *pkg; + dbsync_t *dbs; +} syncpkg_t; + int sync_synctree(); -int downloadfiles(char *server, char *remotepath, char *localpath, PMList *files); +int downloadfiles(PMList *servers, char *localpath, PMList *files); #endif diff --git a/src/util.c b/src/util.c index 1fe2e037..b5930bcf 100644 --- a/src/util.c +++ b/src/util.c @@ -34,6 +34,7 @@ #include "package.h" #include "db.h" #include "util.h" +#include "pacsync.h" #include "pacman.h" extern char* pmo_root; @@ -54,11 +55,9 @@ extern unsigned short pmo_s_sync; extern unsigned short pmo_s_search; extern unsigned short pmo_s_clean; extern unsigned short pmo_s_upgrade; +extern PMList *pmo_noupgrade; -extern char pmc_syncserver[512]; -extern char pmc_syncname[512]; -extern char pmc_syncpath[512]; - +extern PMList *pmc_syncs; extern PMList *pm_targets; /* borrowed and modifed from Per Liden's pkgutils (http://crux.nu) */ @@ -221,6 +220,7 @@ int parseargs(int op, int argc, char **argv) return(0); } +#define min(X, Y) ((X) < (Y) ? (X) : (Y)) int parseconfig(char *configfile) { FILE *fp = NULL; @@ -228,6 +228,8 @@ int parseconfig(char *configfile) char *ptr = NULL; char *key = NULL; int linenum = 0; + char section[256] = ""; + sync_t *sync = NULL; if((fp = fopen(configfile, "r")) == NULL) { perror(configfile); @@ -243,25 +245,126 @@ int parseconfig(char *configfile) if(line[0] == '#') { continue; } - ptr = line; - key = strsep(&ptr, "="); - if(key == NULL || ptr == NULL) { - fprintf(stderr, "syntax error in config file (line %d)\n", linenum); + if(line[0] == '[' && line[strlen(line)-1] == ']') { + /* new config section */ + ptr = line; + ptr++; + strncpy(section, ptr, min(255, strlen(ptr)-1)); + section[min(255, strlen(ptr)-1)] = '\0'; + vprint("config: new section '%s'\n", section); + if(!strlen(section)) { + fprintf(stderr, "config: line %d: bad section name\n", linenum); + return(1); + } + if(!strcmp(section, "local")) { + fprintf(stderr, "config: line %d: %s is reserved and cannot be used as a package tree\n", + linenum, section); + return(1); + } + if(strcmp(section, "options")) { + /* start a new sync record */ + MALLOC(sync, sizeof(sync_t)); + sync->treename = strdup(section); + sync->servers = NULL; + pmc_syncs = list_add(pmc_syncs, sync); + } } else { - trim(key); - key = strtoupper(key); - trim(ptr); - if(!strcmp(key, "SYNC_SERVER")) { - strncpy(pmc_syncserver, ptr, sizeof(pmc_syncserver)-1); - } else if(!strcmp(key, "SYNC_TREE_PATH")) { - strncpy(pmc_syncpath, ptr, sizeof(pmc_syncpath)-1); - } else if(!strcmp(key, "SYNC_TREE_NAME")) { - strncpy(pmc_syncname, ptr, sizeof(pmc_syncname)-1); + /* directive */ + if(!strlen(section)) { + fprintf(stderr, "config: line %d: all directives must belong to a section\n", linenum); + return(1); + } + ptr = line; + key = strsep(&ptr, "="); + if(key == NULL || ptr == NULL) { + fprintf(stderr, "config: line %d: syntax error\n", linenum); + return(1); } else { - fprintf(stderr, "Syntax error in description file line %d\n", linenum); + trim(key); + key = strtoupper(key); + trim(ptr); + if(!strcmp(section, "options")) { + if(!strcmp(key, "NOUPGRADE")) { + char *p = ptr; + char *q; + while((q = strchr(p, ' '))) { + *q = '\0'; + pmo_noupgrade = list_add(pmo_noupgrade, strdup(p)); + vprint("config: noupgrade: %s\n", p); + p = q; + p++; + } + pmo_noupgrade = list_add(pmo_noupgrade, strdup(p)); + vprint("config: noupgrade: %s\n", p); + } else { + fprintf(stderr, "config: line %d: syntax error\n", linenum); + return(1); + } + } else { + if(!strcmp(key, "SERVER")) { + /* parse our special url */ + server_t *server; + char *p; + + MALLOC(server, sizeof(server_t)); + server->server = server->path = NULL; + server->islocal = 0; + + p = strstr(ptr, "://"); + if(p == NULL) { + fprintf(stderr, "config: line %d: bad server location\n", linenum); + return(1); + } + *p = '\0'; + p++; p++; p++; + if(p == NULL || *p == '\0') { + fprintf(stderr, "config: line %d: bad server location\n", linenum); + return(1); + } + server->islocal = !strcmp(ptr, "local"); + if(!server->islocal) { + char *slash; + /* no http support yet */ + if(strcmp(ptr, "ftp")) { + fprintf(stderr, "config: line %d: protocol %s is not supported\n", linenum, ptr); + return(1); + } + /* split the url into domain and path */ + slash = strchr(p, '/'); + if(slash == NULL) { + /* no path included, default to / */ + server->path = strdup("/"); + } else { + /* add a trailing slash if we need to */ + if(slash[strlen(slash)-1] == '/') { + server->path = strdup(slash); + } else { + MALLOC(server->path, strlen(slash)+2); + sprintf(server->path, "%s/", slash); + } + *slash = '\0'; + } + server->server = strdup(p); + } else { + /* add a trailing slash if we need to */ + if(p[strlen(p)-1] == '/') { + server->path = strdup(p); + } else { + MALLOC(server->path, strlen(p)+2); + sprintf(server->path, "%s/", p); + } + } + /* add to the list */ + vprint("config: %s: server: %s %s\n", section, server->server, server->path); + sync->servers = list_add(sync->servers, server); + } else { + fprintf(stderr, "config: line %d: syntax error\n", linenum); + return(1); + } + } + line[0] = '\0'; } } - line[0] = '\0'; } fclose(fp); @@ -272,7 +375,7 @@ int copyfile(char *src, char *dest) { FILE *in, *out; size_t len; - char buf[1025]; + char buf[4097]; in = fopen(src, "r"); if(in == NULL) { @@ -283,7 +386,7 @@ int copyfile(char *src, char *dest) return(1); } - while((len = fread(buf, 1, 1024, in))) { + while((len = fread(buf, 1, 4096, in))) { fwrite(buf, 1, len, out); } -- cgit v1.2.3-24-g4f1b