summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJudd Vinet <judd@archlinux.org>2002-02-25 20:23:38 +0100
committerJudd Vinet <judd@archlinux.org>2002-02-25 20:23:38 +0100
commitd53b2011b1406a4784995f4043added5c04588ce (patch)
tree3b4b9fd73a8ac0121c7b6fac9185281f08fd7c86
downloadpacman-d53b2011b1406a4784995f4043added5c04588ce.tar.gz
pacman-d53b2011b1406a4784995f4043added5c04588ce.tar.xz
Imported from pacman-1.0.tar.gz
-rw-r--r--COPYING340
-rw-r--r--ChangeLog5
-rw-r--r--Makefile79
-rw-r--r--README48
-rw-r--r--TODO24
-rwxr-xr-xinstallworld25
-rw-r--r--libtar-1.2.4.tar.gzbin0 -> 73513 bytes
-rwxr-xr-xmakepkg88
-rw-r--r--makepkg.conf8
-rwxr-xr-xmakeworld29
-rw-r--r--pacman.8.in72
-rw-r--r--pacman.c980
-rw-r--r--pacman.h64
13 files changed, 1762 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..96e45911
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 00000000..6a9a6b89
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,5 @@
+VERSION DESCRIPTION
+------------------------------------------------------------------
+ - Changed db_find_conflicts() to ignore directories
+1.0 - Initial Release
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..58de8a2a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,79 @@
+#
+# pacman
+#
+# Copyright (c) 2002 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.
+#
+
+# NOTE: Since pacman is compiled statically, you will need the static
+# libraries for zlib and glibc.
+
+DESTDIR =
+BINDIR = /usr/bin
+MANDIR = /usr/man
+ETCDIR = /etc
+
+VERSION = 1.0
+LIBTAR_VERSION = 1.2.4
+
+CXX = gcc
+CXXFLAGS += -DNDEBUG -O2 -Wall -pedantic -fno-exceptions -fno-rtti \
+ -D_GNU_SOURCE -DVERSION=\"$(VERSION)\" -Ilibtar-$(LIBTAR_VERSION)/lib
+LDFLAGS += -static -Llibtar-$(LIBTAR_VERSION)/lib -ltar -lz
+
+OBJECTS = pacman.o
+
+all: libtar pacman man
+
+pacman: $(OBJECTS)
+ $(CXX) $(OBJECTS) -o $@ $(LDFLAGS)
+
+pacman.o: pacman.c pacman.h
+ $(CXX) $(CXXFLAGS) -c pacman.c
+
+man: pacman.8
+
+%: %.in
+ sed -e "s/#VERSION#/$(VERSION)/" $< > $@
+
+dist: distclean
+ (cd ..; tar czvf pacman-$(VERSION).tar.gz pacman-$(VERSION))
+
+libtar:
+ (tar xzf libtar-$(LIBTAR_VERSION).tar.gz; \
+ cd libtar-$(LIBTAR_VERSION); \
+ LDFLAGS="" ./configure --disable-encap --disable-encap-install; \
+ make;)
+
+install: all
+ install -D -m0755 pacman $(DESTDIR)$(BINDIR)/pacman
+ install -D -m0644 pacman.8 $(DESTDIR)$(MANDIR)/man8/pacman.8
+ install -D -m0755 makepkg $(DESTDIR)$(BINDIR)/makepkg
+ install -D -m0755 makeworld $(DESTDIR)$(BINDIR)/makeworld
+ @echo ""
+ @echo "*** If this is a first-time install, you should copy makepkg.conf"
+ @echo "*** to /etc now."
+ @echo ""
+
+clean:
+ rm -f *~ *.o *.8
+
+distclean: clean
+ rm -f pacman
+ rm -rf libtar-$(LIBTAR_VERSION)
+
+# End of file
diff --git a/README b/README
new file mode 100644
index 00000000..26cab790
--- /dev/null
+++ b/README
@@ -0,0 +1,48 @@
+
+ pacman - Package Management Utility
+
+ by Judd Vinet <jvinet@zeroflux.org>
+
+DESCRIPTION:
+------------
+ pacman is a utility which manages software packages in Linux. It uses
+ simple .tar.gz files as a package format, and maintains a text-based
+ package database, just in case some hand tweaking is necessary.
+
+ pacman does not strive to "do everything." It will add, remove and
+ upgrade packages in the system, and it will allow you to query the
+ package database for installed packages, files and owners.
+
+ Plans exist for dependency checking and remote file fetching, as well.
+ See TODO for more info.
+
+
+INSTALL:
+--------
+$ make install
+or
+$ make DESTDIR=/your/path/here install
+
+If your man files are located in a directory other than /usr/man, you may
+want to edit Makefile and modify the MANDIR line accordingly.
+
+Note: Since pacman is compiled statically, you will need the static libraries
+ for glibc and zlib.
+
+
+BUGS:
+-----
+If you find bugs (which is quite likely at version 1.0), please submit
+them to <jvinet@zeroflux.org> with specific information, such as your
+commandline, the nature of the bug, and even the package database, if
+it helps.
+
+
+COPYRIGHT:
+----------
+pacman is Copyright (c) 2002 Judd vinet <jvinet@zeroflux.org> and is
+licensed through the GNU General Public License (see COPYING).
+
+pacman uses "libtar", a library for reading/writing tar-files. This
+library is Copyright (c) 1998-2001 Mark D. Roth <roth@uiuc.edu> (see
+libtar-X.X.X/COPYRIGHT for further details).
diff --git a/TODO b/TODO
new file mode 100644
index 00000000..a08e2597
--- /dev/null
+++ b/TODO
@@ -0,0 +1,24 @@
+These are things that should get done at some point. Some are simple,
+others are more complex and could be a while in development.
+
+- add a [sibling] option to .PKGINFO -- used when only one of
+ the siblings can be installed at a time (eg, bsdinit,sysvinit)
+- handle wildcards on the command line
+- sort packages by package name in pacman.db
+- manage conditional file installs (ie, 'info' pages)
+- make sure program consistently returns a non-zero return code on
+ error, so scripts can rely on it
+- maybe add a 'confirm every action' option for doing paranoid installs
+- add better directory tracking
+ - use crux's pkgmk technique. $(make prefix=$PKG/usr install) then just
+ $(cd $PKG; tar czf $pkg.tar.gz *)
+- add a consistency check operation
+- change char[xxx] to char[PATH_MAX]
+- add file locking to db
+- add a --dbpath option
+- dependency checking
+- fetch files via ftp
+ - need to manage foreign package lists like apt
+- handle .save files better (for more than just .conf files)
+- upgrade currently does a double db backup; not really desirable
+
diff --git a/installworld b/installworld
new file mode 100755
index 00000000..fd155622
--- /dev/null
+++ b/installworld
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+if [ "$1" = "" ]; then
+ echo "usage: $0 <pkg_directory>"
+ echo ""
+ echo "call this while in the root of the install tree and"
+ echo "pass it the path of the directory containing packages"
+ echo "to be installed"
+ echo ""
+ exit
+fi
+
+echo "Initializing pacman database..."
+mkdir -p var/lib/pacman && touch var/lib/pacman/pacman.db
+
+for pkg in `find $1/*`; do
+ echo "==> $pkg" >>install.log
+ echo "==> $pkg"
+ pacman -A -r . $pkg 2>&1 >>install.log
+done
+
+echo "Syncing..."
+sync
+
+echo "Done."
diff --git a/libtar-1.2.4.tar.gz b/libtar-1.2.4.tar.gz
new file mode 100644
index 00000000..24291e55
--- /dev/null
+++ b/libtar-1.2.4.tar.gz
Binary files differ
diff --git a/makepkg b/makepkg
new file mode 100755
index 00000000..b9ad4bcb
--- /dev/null
+++ b/makepkg
@@ -0,0 +1,88 @@
+#!/bin/bash
+
+me=`basename $0`
+myver='1.0'
+startdir=`pwd`
+
+[ -f /etc/makepkg.conf ] && . /etc/makepkg.conf
+
+strip_url() {
+ echo $1 | sed 's|^.*://.*/||g'
+}
+
+if [ ! -f $startdir/PKGBUILD ]; then
+ echo "error: $startdir/PKGBUILD does not exist!"
+ exit
+fi
+
+. $startdir/PKGBUILD
+
+# extract source
+echo "==> Acquiring/Extracting Sources..."
+mkdir -p src pkg
+cd $startdir/src
+for netfile in ${source[@]}; do
+ file=`strip_url $netfile`
+ if [ -f ../$file ]; then
+ echo "==> Found $file in build dir"
+ cp ../$file .
+ elif [ -f /var/cache/pkg/$file ]; then
+ echo "==> Using local copy of $file"
+ cp /var/cache/pkg/$file .
+ else
+ echo "==> Downloading $file"
+ wget --passive-ftp --no-directories --tries=3 --waitretry=3 $netfile
+ if [ ! -f $file ]; then
+ echo "==> ERROR: Failed to download $file"
+ echo "==> Aborting..."
+ exit 1
+ fi
+ mkdir -p /var/cache/pkg && cp $file /var/cache/pkg
+ fi
+ 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" ;;
+ *.zip)
+ cmd="unzip -qq $file" ;;
+ *)
+ cmd="cp ../$file ." ;;
+ esac
+ echo "$cmd"
+ $cmd
+done
+
+# build
+echo "==> Building Package..."
+build
+
+# write the .PKGINFO file
+echo "==> Generating .PKGINFO file..."
+cd $startdir/pkg
+echo "# Generated by makepkg $myver" >.PKGINFO
+echo -n "# " >>.PKGINFO
+date >>.PKGINFO
+echo "pkgname = $pkgname" >>.PKGINFO
+echo "pkgver = $pkgver-$pkgrel" >>.PKGINFO
+
+# remove info files
+cd $startdir
+rm -rf pkg/usr/info pkg/usr/share/info
+
+# strip binaries
+cd $startdir
+echo "==> Stripping debugging symbols from libraries..."
+find pkg/{,usr,usr/local}/lib -type f \
+ -exec /usr/bin/strip --strip-debug '{}' ';'
+echo "==> Stripping symbols from binaries..."
+find pkg/{,usr,usr/local}/{bin,sbin} -type f \
+ -exec /usr/bin/strip '{}' ';'
+
+# tar it up
+echo "==> Compressing package..."
+cd $startdir/pkg
+tar czvf $startdir/$pkgname-$pkgver-$pkgrel.pkg.tar.gz .PKGINFO * >../filelist
+
+cd $startdir
+echo "==> Finished";
diff --git a/makepkg.conf b/makepkg.conf
new file mode 100644
index 00000000..0532f589
--- /dev/null
+++ b/makepkg.conf
@@ -0,0 +1,8 @@
+#
+# /etc/pkgmake.conf
+#
+
+export CFLAGS="-O2 -march=i686 -pipe"
+export CXXFLAGS="-O2 -march=i686 -pipe"
+
+# End of file
diff --git a/makeworld b/makeworld
new file mode 100755
index 00000000..a6c0b470
--- /dev/null
+++ b/makeworld
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+toplevel=`pwd`
+
+if [ $# -lt 1 ]; then
+ echo "usage: $0 <destdir>"
+ exit 1
+fi
+
+for port in `find $toplevel -type d -maxdepth 1 -mindepth 1 | sort`; do
+ cd $port
+ if [ -f PKGBUILD ]; then
+ . PKGBUILD
+ donebuild=0
+ if [ ! -f $1/$pkgname-$pkgver-$pkgrel.pkg.tar.gz ]; then
+ makepkg
+ rm -rf pkg src
+ mv -v $pkgname-$pkgver-$pkgrel.pkg.tar.gz $1/
+ donebuild=1
+ fi
+ d=`date +"[%b %d %H:%M]"`
+ echo -n "$d " >>$toplevel/build.log
+ if [ $donebuild = 1 ]; then
+ echo "$pkgname was built successfully" >>$toplevel/build.log
+ else
+ echo "$pkgname already built -- skipping" >>$toplevel/build.log
+ fi
+ fi
+done
diff --git a/pacman.8.in b/pacman.8.in
new file mode 100644
index 00000000..2db57ced
--- /dev/null
+++ b/pacman.8.in
@@ -0,0 +1,72 @@
+.TH pacman 8 "Feb 10, 2002" "pacman #VERSION#" ""
+.SH NAME
+pacman \- package manager utility
+.SH SYNOPSIS
+\fBpacman <operation> [options] <package>\fP
+.SH DESCRIPTION
+\fBpacman\fP is a \fIpackage management\fP utility. Package
+information is maintained in a basic text format for easy
+tweaking, if necessary, and packages are in a standard
+\fIgzipped tar\fP format.
+.SH OPERATIONS
+.TP
+.B "\-A, \-\-add"
+Add a package to the system. Package will be uncompressed
+into the installation root and the database will be updated.
+.TP
+.B "\-R, \-\-remove"
+Remove a package from the system. Files belonging to the
+specified package will be deleted, and the database will
+be updated. Note that files with \fI.conf\fP extensions will
+be renamed with \fI.conf.save\fP extensions.
+.TP
+.B "\-U, \-\-upgrade"
+Upgrade a package. This is essentially a "remove-then-install"
+process. Files with \fI.conf\fP extensions will be saved.
+.TP
+.B "\-Q, \-\-query"
+Query the package database. This operation allows you to
+view installed packages and their files. See \fBQUERY OPTIONS\fP
+below.
+.TP
+.B "\-V, \-\-version"
+Display version and exit.
+.TP
+.B "\-h, \-\-help"
+Display syntax for the given operation. If no operation was
+supplied, then the general syntax is shown.
+.SH QUERY OPTIONS
+.TP
+.B "\-o, \-\-owns <file>"
+Output the name of the package that owns <file>.
+.TP
+.B "\-l, \-\-list"
+Instead of outputting the package name, output the list of
+files owned by the package.
+.TP
+.B "\-i, \-\-info"
+Output the .PKGINFO file contained in <package>. This option
+can only be used with the \fB-p\fP option.
+.SH OPTIONS
+.TP
+.B "\-v, \-\-verbose"
+Output more status and error messages.
+.TP
+.B "\-f, \-\-force"
+Force installation, overwriting conflicting files. If the package
+that is about to be installed contains files that are already
+installed this option will cause all those files to be overwritten.
+This option should be used with care, preferably not at all.
+.TP
+.B "\-r, \-\-root <path>"
+Specify alternative installation root (default is "/"). This
+should \fInot\fP be used as a way to install software into
+e.g. /usr/local instead of /usr. Instead this should be used
+if you want to install a package on a temporary mounted partition,
+which is "owned" by another system. By using this option you not only
+specify where the software should be installed, but you also
+specify which package database to use.
+.SH AUTHOR
+.nf
+Judd Vinet <jvinet@zeroflux.org>
+.fi
diff --git a/pacman.c b/pacman.c
new file mode 100644
index 00000000..60c99726
--- /dev/null
+++ b/pacman.c
@@ -0,0 +1,980 @@
+/**
+ * pacman
+ *
+ * Copyright (c) 2002 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.
+ */
+#include "pacman.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <libtar.h>
+#include <zlib.h>
+
+/* borrowed and modifed from Per Liden's pkgutils (http://crux.nu) */
+static int gzopen_frontend(char *pathname, int oflags, int mode)
+{
+ char* gzoflags;
+ int fd;
+ gzFile gzf;
+
+ switch (oflags & O_ACCMODE) {
+ case O_WRONLY:
+ gzoflags = "w";
+ break;
+ case O_RDONLY:
+ gzoflags = "r";
+ break;
+ case O_RDWR:
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if((fd = open(pathname, oflags, mode)) == -1) {
+ return -1;
+ }
+ if((oflags & O_CREAT) && fchmod(fd, mode)) {
+ return -1;
+ }
+ if(!(gzf = gzdopen(fd, gzoflags))) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return (int)gzf;
+}
+
+static tartype_t gztype = {
+ (openfunc_t) gzopen_frontend,
+ (closefunc_t)gzclose,
+ (readfunc_t) gzread,
+ (writefunc_t)gzwrite
+};
+
+/*
+ * GLOBALS
+ *
+ */
+FILE* dbfp = NULL;
+char* dbpath = PKGDB;
+char* pkgname = NULL;
+char* pkgver = NULL;
+
+char* pmo_root = NULL;
+unsigned short pmo_verbose = 0;
+unsigned short pmo_force = 0;
+unsigned short pmo_upgrade = 0;
+unsigned short pmo_nosave = 0;
+unsigned short pmo_nofunc = 0;
+unsigned short pmo_q_isfile = 0;
+unsigned short pmo_q_info = 0;
+unsigned short pmo_q_list = 0;
+char* pmo_q_owns = NULL;
+
+pkginfo_t** packages = NULL;
+unsigned int pkgcount = 0;
+
+
+int main(int argc, char* argv[])
+{
+ pm_opfunc_t op_func;
+ char* funcvar = NULL;
+ int ret = 0;
+
+ /* default root */
+ pmo_root = (char*)malloc(2);
+ strcpy(pmo_root, "/");
+
+ if(argc < 2) {
+ usage(PM_MAIN, (char*)basename(argv[0]));
+ return(0);
+ }
+
+ /* determine the requested operation and pass off to */
+ /* the handler function */
+ if(!strcmp(argv[1], "-A") || !strcmp(argv[1], "--add")) {
+ op_func = pacman_add;
+ funcvar = parseargs(PM_ADD, argc, argv);
+ } else if(!strcmp(argv[1], "-R") || !strcmp(argv[1], "--remove")) {
+ op_func = pacman_remove;
+ funcvar = parseargs(PM_REMOVE, argc, argv);
+ } else if(!strcmp(argv[1], "-Q") || !strcmp(argv[1], "--query")) {
+ op_func = pacman_query;
+ funcvar = parseargs(PM_QUERY, argc, argv);
+ } else if(!strcmp(argv[1], "-U") || !strcmp(argv[1], "--upgrade")) {
+ op_func = pacman_upgrade;
+ funcvar = parseargs(PM_UPGRADE, argc, argv);
+ } else if(!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+ usage(PM_MAIN, (char*)basename(argv[0]));
+ return(1);
+ } else if(!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")) {
+ version();
+ return(1);
+ } else {
+ printf("error: invalid operation\n\n");
+ usage(PM_MAIN, (char*)basename(argv[0]));
+ return(1);
+ }
+
+ if(funcvar == NULL && op_func != pacman_query) {
+ return(1);
+ }
+ vprint("Installation Root: %s\n", pmo_root);
+ vprint("Package Name: %s\n", funcvar);
+
+ /* check for db existence */
+ if(pmo_root != NULL) {
+ /* trim the trailing '/' if there is one */
+ if((int)rindex(pmo_root, '/') == ((int)pmo_root)+strlen(pmo_root)-1) {
+ pmo_root[strlen(pmo_root)-1] = '\0';
+ }
+ free(dbpath);
+ dbpath = (char*)malloc(strlen(pmo_root) + strlen(PKGDB) + 1);
+ strcpy(dbpath, pmo_root);
+ dbpath = (char*)strcat(dbpath, PKGDB);
+ }
+ vprint("Using package DB: %s\n", dbpath);
+
+ ret = db_open(dbpath);
+ if(ret == 1) {
+ printf("error: Could not open package database file!\n");
+ printf(" Check to see that %s exists.\n", dbpath);
+ printf(" If not, you may simply create it by \"touch\"-ing it.\n");
+ return(1);
+ }
+ if(ret == 2) {
+ printf("error: Database is corrupt! You may need to use the backup database.\n");
+ printf(" I hope you like tweaking... ;-)\n");
+ return(1);
+ }
+
+ /* start the requested operation */
+ if(!pmo_nofunc) {
+ ret = op_func(funcvar);
+ if(ret) {
+ printf("There were errors\n");
+ }
+ }
+
+ fclose(dbfp);
+ return(0);
+}
+
+int pacman_add(char* pkgfile)
+{
+ int i, errors = 0;
+ TAR* tar;
+ char* errmsg = NULL;
+ char* expath = NULL;
+ char* newpath = NULL;
+ fileset_t files = NULL;
+ unsigned int filecount = 0;
+ struct stat buf;
+
+ /* Populate the file list */
+ filecount = load_pkg(pkgfile, &files, 0);
+ if(filecount == 0) {
+ return(1);
+ }
+
+ /* Now check for conflicts in the db */
+ vprint("Looking for DB conflicts...\n");
+ if((i = db_find_conflicts(files, filecount)) == 1) {
+ if(pmo_force) {
+ printf("\nInstalling package anyway...\n");
+ printf(" You might have duplicate entries in your package\n");
+ printf(" database now. You may want to edit it and remove\n");
+ printf(" one of the copies.\n\n");
+ } else {
+ printf("Aborting...\n");
+ printf(" (use -f to override)\n\n");
+ return(1);
+ }
+ } else if(i == 2) {
+ return(1);
+ } else {
+ vprint("No DB conflicts found\n");
+ }
+
+ /* see if this is an upgrade. if so, remove the old package first */
+ if(pmo_upgrade) {
+ vprint("Removing old package first...\n");
+ if(pacman_remove(pkgname)) {
+ printf("\nUpgrade aborted.\n");
+ return(1);
+ }
+ }
+
+ /* open the .tar.gz package */
+ if(tar_open(&tar, pkgfile, &gztype, O_RDONLY, 0, TAR_GNU) == -1) {
+ perror("could not open package");
+ return(1);
+ }
+ vprint("Extracting files...\n");
+ for(i = 0; !th_read(tar); i++) {
+ if(!strcmp(th_get_pathname(tar), ".PKGINFO")) {
+ tar_skip_regfile(tar);
+ continue;
+ }
+ /* build the new pathname relative to pmo_root */
+ expath = (char*)malloc(strlen(th_get_pathname(tar))+strlen(pmo_root)+2);
+ strcpy(expath, pmo_root);
+ strcat(expath, "/");
+ strcat(expath, th_get_pathname(tar));
+ vprint(" %s\n", expath);
+ if(!stat(expath, &buf)) {
+ /* if the file ends in .conf, back it up */
+ if(!strcmp((char*)(expath+strlen(expath)-5), ".conf")) {
+ newpath = (char*)realloc(newpath, strlen(expath)+6);
+ strcpy(newpath, expath);
+ strcat(newpath, ".save");
+ rename(expath, newpath);
+ printf("%s renamed to %s\n", expath, newpath);
+ }
+ }
+ if(tar_extract_file(tar, expath)) {
+ errmsg = strerror(errno);
+ printf("could not extract %s: %s\n", th_get_pathname(tar), errmsg);
+ errors = 1;
+ }
+ free(expath);
+ }
+ tar_close(tar);
+ vprint("Done.\n");
+ if(errors) {
+ printf("There were errors. No database update was performed.\n");
+ } else {
+ vprint("Updating database...\n");
+ if(db_update(files, filecount)) {
+ printf("error: Could not update database! The database may not\n");
+ printf(" be in a sane state!\n");
+ return(1);
+ }
+ vprint("Done.\n");
+ }
+ return(0);
+}
+
+int pacman_remove(char* pkgfile)
+{
+ int found = 0, done = 0;
+ int i;
+ char line[255];
+ fileset_t files = NULL;
+ unsigned int filecount = 0;
+ struct stat buf;
+ char* newpath = NULL;
+
+ if(pkgfile == NULL) {
+ return(0);
+ }
+
+ /* find the package's filelist in the db */
+ rewind(dbfp);
+ while(!found && !feof(dbfp)) {
+ fgets(line, 255, dbfp);
+ strcpy(line, trim(line));
+ if(!strcmp(line, pkgfile)) {
+ /* read the version */
+ fgets(line, 255, dbfp);
+ found = 1;
+ }
+ }
+ if(!found) {
+ printf("Cannot remove %s: Package was not found.\n", pkgfile);
+ return(1);
+ }
+
+ while(!done) {
+ fgets(line, 255, dbfp);
+ strcpy(line, trim(line));
+ if(strlen(line)) {
+ /* add the path to the list */
+ files = (fileset_t)realloc(files, (++filecount) * sizeof(char*));
+ files[filecount-1] = (char*)malloc(strlen(line)+1);
+ strcpy(files[filecount-1], line);
+ } else {
+ done = 1;
+ }
+ }
+ /* iterate through the list backwards, unlinking files */
+ for(i = filecount-1; i >= 0; i--) {
+ if(lstat(files[i], &buf)) {
+ vprint("file %s does not exist\n", files[i]);
+ continue;
+ }
+ if(S_ISDIR(buf.st_mode)) {
+ vprint(" removing directory %s\n", files[i]);
+ if(rmdir(files[i])) {
+ /* this is okay, other packages are probably using it. */
+ /* perror("cannot remove directory"); */
+ }
+ } else {
+ /* if the file ends in .conf, back it up */
+ if(!pmo_nosave && !strcmp((char*)(files[i]+strlen(files[i])-5), ".conf")) {
+ newpath = (char*)realloc(newpath, strlen(files[i])+6);
+ strcpy(newpath, files[i]);
+ strcat(newpath, ".save");
+ rename(files[i], newpath);
+ printf("%s renamed to %s\n", files[i], newpath);
+ } else {
+ vprint(" unlinking %s\n", files[i]);
+ if(unlink(files[i])) {
+ perror("cannot remove file");
+ }
+ }
+ }
+ }
+
+ /* now splice this name out of the packages list */
+ found = 0;
+ for(i = 0; i < pkgcount-1; i++) {
+ if(found) {
+ packages[i] = packages[i+1];
+ } else {
+ if(!strcmp(packages[i]->name, pkgfile)) {
+ found = 1;
+ if(i < pkgcount-1) {
+ packages[i] = packages[i+1];
+ }
+ }
+ }
+ }
+ /* drop the last item */
+ packages = (pkginfo_t**)realloc(packages, (--pkgcount)*sizeof(pkginfo_t*));
+
+ /* and commit the db */
+ return(db_update(NULL, 0));
+}
+
+int pacman_query(char* pkgfile)
+{
+ char *str = NULL;
+ char name[255];
+ char ver[255];
+ char line[255];
+ int found = 0;
+ int done = 0;
+ int i;
+ unsigned int filecount = 0;
+ fileset_t files = NULL;
+
+ /* output info for a .tar.gz package */
+ if(pmo_q_isfile) {
+ filecount = load_pkg(pkgfile, &files, pmo_q_info);
+ if(pmo_q_list) {
+ for(i = 0; i < filecount; i++) {
+ if(strcmp(files[i], ".PKGINFO")) {
+ printf("%s\n", files[i]);
+ }
+ }
+ } else {
+ printf("%s %s\n", pkgname, pkgver);
+ }
+
+ return(0);
+ }
+
+ /* determine the owner of a file */
+ if(pmo_q_owns != NULL) {
+ rewind(dbfp);
+ while(!found && !feof(dbfp)) {
+ fgets(name, 255, dbfp);
+ strcpy(name, trim(name));
+ fgets(ver, 255, dbfp);
+ strcpy(ver, trim(ver));
+ strcpy(line, " ");
+ while(strlen(line) && !feof(dbfp)) {
+ fgets(line, 255, dbfp);
+ strcpy(line, trim(line));
+ str = line;
+ str += strlen(pmo_root);
+ if(!strcmp(line, pmo_q_owns)) {
+ printf("%s %s\n", name, ver);
+ return(0);
+ }
+ }
+ }
+ printf("No package owns this file.\n");
+ return(0);
+ }
+
+ /* find packages in the db */
+ rewind(dbfp);
+ while(!done) {
+ found = 0;
+ while(!found && !feof(dbfp)) {
+ fgets(name, 255, dbfp);
+ strcpy(name, trim(name));
+ if(pkgfile == NULL || (pkgfile != NULL && !strcmp(name, pkgfile))) {
+ /* read the version */
+ fgets(ver, 255, dbfp);
+ strcpy(ver, trim(ver));
+ found = 1;
+ if(pkgfile != NULL) {
+ done = 1;
+ }
+ }
+ }
+ if(feof(dbfp)) {
+ if(pkgfile != NULL && !found) {
+ printf("Package was not found in database.\n");
+ }
+ break;
+ }
+ found = 0;
+ while(!found) {
+ fgets(line, 255, dbfp);
+ strcpy(line, trim(line));
+ if(strlen(line)) {
+ if(pmo_q_list) {
+ printf("%s%s\n", pmo_root, line);
+ }
+ } else {
+ found = 1;
+ }
+ }
+ if(!pmo_q_list) {
+ printf("%s %s\n", name, ver);
+ }
+ if(feof(dbfp)) {
+ done = 1;
+ }
+ }
+
+ return(0);
+}
+
+int pacman_upgrade(char* pkgfile)
+{
+ /* this is basically just a remove,add process. pacman_add() will */
+ /* handle it */
+ pmo_upgrade = 1;
+ pacman_add(pkgfile);
+ return(0);
+}
+
+/*
+ * Populate the package file list
+ * pkgfile: filename of package
+ * listptr: this will be set to the new fileset_t
+ *
+ * Returns: the number of filenames read in the package, or 0 on error
+ *
+ */
+int load_pkg(char* pkgfile, fileset_t* listptr, unsigned short output)
+{
+ char* expath;
+ char* descfile;
+ int i;
+ TAR* tar;
+ unsigned int filecount = 0;
+ fileset_t files = NULL;
+
+ descfile = (char*)malloc(strlen("/tmp/pacman_XXXXXX")+1);
+ strcpy(descfile, "/tmp/pacman_XXXXXX");
+
+ if(tar_open(&tar, pkgfile, &gztype, O_RDONLY, 0, TAR_GNU) == -1) {
+ perror("could not open package");
+ return(0);
+ }
+ vprint("Loading filelist from package...\n");
+ for(i = 0; !th_read(tar); i++) {
+ if(!strcmp(th_get_pathname(tar), ".PKGINFO")) {
+ /* extract this file into /tmp. it has info for us */
+ vprint("Found package description file.\n");
+ mkstemp(descfile);
+ tar_extract_file(tar, descfile);
+ parse_descfile(descfile, output);
+ continue;
+ }
+ /* build the new pathname relative to pmo_root */
+ expath = (char*)malloc(strlen(th_get_pathname(tar))+strlen(pmo_root)+2);
+ strcpy(expath, pmo_root);
+ strcat(expath, "/");
+ strcat(expath, th_get_pathname(tar));
+ /* add the path to the list */
+ files = (fileset_t)realloc(files, (++filecount) * sizeof(char*));
+ files[filecount-1] = expath;
+
+ if(TH_ISREG(tar) && tar_skip_regfile(tar)) {
+ perror("bad package file");
+ return(0);
+ }
+ expath = NULL;
+ }
+ tar_close(tar);
+
+ if(pkgname == NULL || pkgver == NULL) {
+ printf("The current version of Pacman requires a .PKGINFO file\n");
+ printf("present in the .tar.gz archive. This package does not\n");
+ printf("have one.\n");
+ return(0);
+ }
+
+ (*listptr) = files;
+ return(filecount);
+}
+
+/* Open the database file
+ * path: the full pathname of the file
+ */
+int db_open(char* path)
+{
+ char line[255];
+ pkginfo_t* info;
+ dbfp = fopen(path, "r");
+ if(dbfp == NULL) {
+ return(1);
+ }
+ while(!feof(dbfp)) {
+ info = (pkginfo_t*)malloc(sizeof(pkginfo_t));
+ fgets(line, 64, dbfp);
+ if(feof(dbfp)) {
+ break;
+ }
+ strcpy(info->name, trim(line));
+ fgets(line, 32, dbfp);
+ strcpy(info->version, trim(line));
+ /* add to the collective */
+ packages = (pkginfo_t**)realloc(packages, (++pkgcount) * sizeof(pkginfo_t*));
+ packages[pkgcount-1] = info;
+ for(;;) {
+ fgets(line, 255, dbfp);
+ if(feof(dbfp)) {
+ return(2);
+ }
+ if(strlen(trim(line)) == 0) {
+ break;
+ }
+ }
+ }
+
+ return(0);
+}
+
+/* Copy the old database file to a backup and build the
+ * new copy in its place.
+ * files: list of files in the new package, can be null
+ * filecount: number of entries in files
+ *
+ * Returns: 0 on success
+ *
+ */
+int db_update(fileset_t files, unsigned int filecount)
+{
+ FILE* olddb;
+ char* newpath = NULL;
+ char* str = NULL;
+ char name[64];
+ char ver[32];
+ char line[255];
+ int i = 0, found = 0, done = 0;
+
+ /* build the backup pathname */
+ newpath = (char*)malloc(strlen(dbpath)+5);
+ strcpy(newpath, dbpath);
+ strcat(newpath, ".bak");
+
+ /* rename the existing db */
+ fclose(dbfp);
+ rename(dbpath, newpath);
+
+ olddb = fopen(newpath, "r");
+ free(newpath);
+ dbfp = fopen(dbpath, "w");
+ if(olddb == NULL || dbfp == NULL) {
+ return(1);
+ }
+
+ rewind(olddb);
+ while(!feof(olddb)) {
+ if(!fgets(name, 64, olddb)) {
+ break;
+ }
+ strcpy(name, trim(name));
+ fgets(ver, 32, olddb);
+ found = 0;
+ for(i = 0; i < pkgcount && !found; i++) {
+ if(!strcmp(packages[i]->name, name)) {
+ /* it's there... copy the entries over */
+ found = 1;
+ fputs(name, dbfp);
+ fputc('\n', dbfp);
+ fputs(ver, dbfp);
+ for(done = 0; !done;) {
+ fgets(line, 255, olddb);
+ if(found) {
+ fputs(line, dbfp);
+ }
+ if(strlen(trim(line)) == 0 || feof(olddb)) {
+ done = 1;
+ }
+ }
+ }
+ }
+ if(!found) {
+ /* skip through filelist for this package */
+ for(done = 0; !done;) {
+ fgets(line, 255, olddb);
+ if(strlen(trim(line)) == 0 || feof(olddb)) {
+ done = 1;
+ }
+ }
+ }
+ }
+ fclose(olddb);
+
+ /* write the current info */
+ if(files != NULL) {
+ fputs(pkgname, dbfp);
+ fputc('\n', dbfp);
+ fputs(pkgver, dbfp);
+ fputc('\n', dbfp);
+ for(i = 0; i < filecount; i++) {
+ str = files[i];
+ str += strlen(pmo_root);
+ fputs(str, dbfp);
+ fputc('\n', dbfp);
+ }
+ fputs("\n", dbfp);
+ }
+ fclose(dbfp);
+ db_open(dbpath);
+
+ return(0);
+}
+
+/* Check the database for conflicts
+ * files: list of files in the new package
+ * filecount: number of entries in files
+ *
+ * Returns: 0 if no conflicts were found, 1 otherwise
+ *
+ */
+int db_find_conflicts(fileset_t files, unsigned int filecount)
+{
+ int i;
+ char line[255];
+ char name[255];
+ struct stat buf;
+ int conflicts = 0;
+
+ /* CHECK 1: checking db conflicts */
+ rewind(dbfp);
+ while(!feof(dbfp)) {
+ fgets(name, 255, dbfp);
+ strcpy(name, trim(name));
+ if(!pmo_upgrade && !strcmp(name, pkgname)) {
+ printf("error: This package is already installed.\n");
+ printf(" Maybe you should be using --upgrade.\n");
+ return(2);
+ }
+ fgets(line, 255, dbfp);
+ while(!feof(dbfp)) {
+ fgets(line, 255, dbfp);
+ strcpy(line, trim(line));
+ if(!strlen(line)) {
+ break;
+ }
+ if(index(line, '/') == (char*)line && (!pmo_upgrade || strcmp(name,pkgname))) {
+ for(i = 0; i < filecount; i++) {
+ if(!strcmp(line, files[i])) {
+ if(rindex(files[i], '/') == files[i]+strlen(files[i])-1) {
+ /* this filename has a trailing '/', so it's a directory -- skip it. */
+ continue;
+ }
+ printf("conflict: %s already exists in package \"%s\"\n", line, name);
+ conflicts = 1;
+ }
+ }
+ }
+ }
+ }
+
+ /* CHECK 2: checking filesystem conflicts */
+ /* TODO: run filesystem checks for upgrades */
+ for(i = 0; i < filecount && !pmo_upgrade; i++) {
+ if(!stat(files[i], &buf) && !S_ISDIR(buf.st_mode)) {
+ printf("conflict: %s already exists in filesystem\n", files[i]);
+ conflicts = 1;
+ }
+ }
+
+ return(conflicts);
+}
+
+/* Parses the package description file for the current package
+ * descfile: the full pathname of the description file
+ *
+ * Returns: 0 on success, 1 on error
+ *
+ */
+int parse_descfile(char* descfile, unsigned short output)
+{
+ FILE* fp;
+ char line[255];
+ char* ptr = NULL;
+ char* key = NULL;
+ int linenum = 0;
+
+ if((fp = fopen(descfile, "r")) == NULL) {
+ perror(descfile);
+ return(1);
+ }
+
+ while(!feof(fp)) {
+ fgets(line, 255, fp);
+ if(output) {
+ printf("%s", line);
+ }
+ linenum++;
+ strcpy(line, trim(line));
+ if(index(line, '#') == (char*)line) {
+ continue;
+ }
+ if(strlen(line) == 0) {
+ continue;
+ }
+ ptr = line;
+ key = strsep(&ptr, "=");
+ if(key == NULL || ptr == NULL) {
+ printf("Syntax error in description file line %d\n", linenum);
+ } else {
+ key = trim(key);
+ key = strtoupper(key);
+ ptr = trim(ptr);
+ if(!strcmp(key, "PKGNAME")) {
+ pkgname = (char*)malloc(strlen(ptr)+1);
+ strcpy(pkgname, ptr);
+ } else if(!strcmp(key, "PKGVER")) {
+ pkgver = (char*)malloc(strlen(ptr)+1);
+ strcpy(pkgver, ptr);
+ } else if(!strcmp(key, "PKGDESC")) {
+ /* Not used yet */
+ } else {
+ printf("Syntax error in description file line %d\n", linenum);
+ }
+ }
+ line[0] = '\0';
+ }
+ fclose(fp);
+ unlink(descfile);
+ return(0);
+}
+
+/* Parse command-line arguments for each operation
+ * op: the operation code requested
+ * argc: argc
+ * argv: argv
+ *
+ * Returns: the functional variable for that operation
+ * (eg, the package file name for PM_ADD)
+ */
+char* parseargs(int op, int argc, char** argv)
+{
+ char* pkg = NULL;
+ int i;
+
+ for(i = 2; i < argc; i++) {
+ if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
+ pmo_nofunc = 1;
+ usage(op, (char*)basename(argv[0]));
+ return(NULL);
+ } else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) {
+ pmo_verbose = 1;
+ } else if(!strcmp(argv[i], "-f") || !strcmp(argv[i], "--force")) {
+ pmo_force = 1;
+ } else if(!strcmp(argv[i], "-r") || !strcmp(argv[i], "--root")) {
+ i++;
+ if(i >= argc) {
+ printf("error: missing argument for %s\n", argv[i-1]);
+ return(NULL);
+ }
+ free(pmo_root);
+ pmo_root = (char*)malloc(PATH_MAX);
+ if(realpath(argv[i], pmo_root) == NULL) {
+ perror("bad root path");
+ return(NULL);
+ }
+ } else if(!strcmp(argv[i], "-n") || !strcmp(argv[i], "--nosave")) {
+ pmo_nosave = 1;
+ } else if(!strcmp(argv[i], "-o") || !strcmp(argv[i], "--owns")) {
+ /* PM_QUERY only */
+ i++;
+ if(i >= argc) {
+ printf("error: missing argument for %s\n", argv[i-1]);
+ return(NULL);
+ }
+ free(pmo_q_owns);
+ pmo_q_owns = (char*)malloc(PATH_MAX);
+ if(realpath(argv[i], pmo_q_owns) == NULL) {
+ perror("bad path specified for --owns");
+ pmo_nofunc = 1;
+ return(NULL);
+ }
+ } else if(!strcmp(argv[i], "-l") || !strcmp(argv[i], "--list")) {
+ /* PM_QUERY only */
+ pmo_q_list = 1;
+ } else if(!strcmp(argv[i], "-p") || !strcmp(argv[i], "--file")) {
+ /* PM_QUERY only */
+ pmo_q_isfile = 1;
+ } else if(!strcmp(argv[i], "-i") || !strcmp(argv[i], "--info")) {
+ /* PM_QUERY only */
+ pmo_q_info = 1;
+ } else {
+ pkg = argv[i];
+ }
+ }
+
+ if(op != PM_QUERY && pkg == NULL) {
+ printf("error: no package specified\n\n");
+ usage(op, (char*)basename(argv[0]));
+ return(NULL);
+ }
+ if(op == PM_QUERY && pmo_q_isfile && pkg == NULL) {
+ printf("error: no package file specified\n\n");
+ return(NULL);
+ }
+ return(pkg);
+}
+
+/* Display usage/syntax for the specified operation.
+ * op: the operation code requested
+ * myname: basename(argv[0])
+ */
+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 {-Q --query} [options] [package]\n", myname);
+ } else if(op == PM_ADD) {
+ printf("usage: %s {-A --add} [options] <file>\n", myname);
+ printf("options:\n");
+ printf(" -f, --force force install, overwrite conflicting files\n");
+ printf(" -n, --nosave do not save .conf files\n");
+ printf(" -v, --verbose be verbose\n");
+ printf(" -r, --root <path> set an alternative installation root\n");
+ } else if(op == PM_REMOVE) {
+ printf("usage: %s {-R --remove} [options] <package>\n", myname);
+ printf("options:\n");
+ printf(" -n, --nosave do not save .conf files\n");
+ printf(" -v, --verbose be verbose\n");
+ printf(" -r, --root <path> set an alternative installation root\n");
+ } else if(op == PM_UPGRADE) {
+ printf("usage: %s {-U --upgrade} [options] <file>\n", myname);
+ printf("options:\n");
+ printf(" -f, --force force install, overwrite conflicting files\n");
+ printf(" -n, --nosave do not save .conf files\n");
+ printf(" -v, --verbose be verbose\n");
+ printf(" -r, --root <path> set an alternative installation root\n");
+ } else if(op == PM_QUERY) {
+ printf("usage: %s {-Q --query} [options] [package]\n", myname);
+ printf("options:\n");
+ printf(" -r, --root <path> set an alternative installation root\n");
+ printf(" -o, --owns <file> query the package that owns <file>\n");
+ printf(" -l, --list list the contents of the queried package\n");
+ printf(" -i, --info output the .PKGINFO file (only used with -p)\n");
+ printf(" -p, --file if used, then [package] will be the path\n");
+ printf(" to an (uninstalled) package to query\n");
+ }
+}
+
+/* Version
+ */
+void version(void)
+{
+ printf("\n");
+ printf(" .--. Pacman v%s\n", VERSION);
+ 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");
+}
+
+/* Check verbosity option and, if set, print the
+ * string to stdout
+ */
+int vprint(char* fmt, ...)
+{
+ va_list args;
+ if(pmo_verbose) {
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ fflush(stdout);
+ }
+ return(0);
+}
+
+/* Convert a string to uppercase
+ */
+char* strtoupper(char* str)
+{
+ char* ptr = str;
+
+ while(*ptr) {
+ (*ptr) = toupper(*ptr);
+ ptr++;
+ }
+ return str;
+}
+
+/* Trim whitespace and newlines from a string
+ */
+char* trim(char* str)
+{
+ char* start = str;
+ char* end = str + strlen(str);
+ int mid = 0;
+ char ch;
+
+ while(mid < 2) {
+ if(!mid) {
+ ch = *start;
+ if(ch == 10 || ch == 13 || ch == 9 || ch == 32) {
+ start++;
+ } else {
+ mid = 1;
+ }
+ } else {
+ end--;
+ ch = *end;
+ if(ch == 10 || ch == 13 || ch == 9 || ch == 32) {
+ *end = '\0';
+ } else {
+ mid = 2;
+ }
+ }
+ }
+ return(start);
+}
+
+/* vim: set ts=2 noet: */
diff --git a/pacman.h b/pacman.h
new file mode 100644
index 00000000..c9f4fdb0
--- /dev/null
+++ b/pacman.h
@@ -0,0 +1,64 @@
+/*
+ * pacman
+ *
+ * Copyright (c) 2002 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.
+ */
+#ifndef PACMAN_H
+#define PACMAN_H
+
+#define VERSION "1.0"
+
+#define PKGEXT ".tar.gz"
+#define PKGDB "/var/lib/pacman/pacman.db"
+
+/* Operations */
+#define PM_MAIN 0
+#define PM_ADD 1
+#define PM_REMOVE 2
+#define PM_QUERY 3
+#define PM_UPGRADE 4
+
+typedef int (*pm_opfunc_t)(char*);
+typedef char** fileset_t;
+typedef struct __pkginfo_t {
+ char version[32];
+ char name[64];
+} pkginfo_t;
+
+int pacman_add(char* pkgfile);
+int pacman_remove(char* pkgfile);
+int pacman_query(char* pkgfile);
+int pacman_upgrade(char* pkgfile);
+
+int db_open(char* path);
+int db_update(fileset_t files, unsigned int filecount);
+int db_find_conflicts(fileset_t files, unsigned int filecount);
+int load_pkg(char* pkgfile, fileset_t* listptr, unsigned short output);
+
+int vprint(char* fmt, ...);
+void usage(int op, char* myname);
+void version(void);
+char* parseargs(int op, int argc, char** argv);
+int parse_descfile(char* descfile, unsigned short output);
+char* trim(char* str);
+char* strtoupper(char* str);
+static int gzopen_frontend(char *pathname, int oflags, int mode);
+
+#endif /* PACMAN_H */
+
+/* vim: set ts=2 noet: */