From d53b2011b1406a4784995f4043added5c04588ce Mon Sep 17 00:00:00 2001 From: Judd Vinet Date: Mon, 25 Feb 2002 19:23:38 +0000 Subject: Imported from pacman-1.0.tar.gz --- COPYING | 340 ++++++++++++++++++ ChangeLog | 5 + Makefile | 79 +++++ README | 48 +++ TODO | 24 ++ installworld | 25 ++ libtar-1.2.4.tar.gz | Bin 0 -> 73513 bytes makepkg | 88 +++++ makepkg.conf | 8 + makeworld | 29 ++ pacman.8.in | 72 ++++ pacman.c | 980 ++++++++++++++++++++++++++++++++++++++++++++++++++++ pacman.h | 64 ++++ 13 files changed, 1762 insertions(+) create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 Makefile create mode 100644 README create mode 100644 TODO create mode 100755 installworld create mode 100644 libtar-1.2.4.tar.gz create mode 100755 makepkg create mode 100644 makepkg.conf create mode 100755 makeworld create mode 100644 pacman.8.in create mode 100644 pacman.c create mode 100644 pacman.h 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. + + + Copyright (C) 19yy + + 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. + + , 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 +# +# 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 + +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 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 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 (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 " + 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 Binary files /dev/null and b/libtar-1.2.4.tar.gz 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 " + 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 [options] \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 " +Output the name of the package that owns . +.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 . 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 " +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 +.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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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] \n", myname); + printf(" %s {-R --remove} [options] \n", myname); + printf(" %s {-U --upgrade} [options] \n", myname); + printf(" %s {-Q --query} [options] [package]\n", myname); + } else if(op == PM_ADD) { + printf("usage: %s {-A --add} [options] \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 set an alternative installation root\n"); + } else if(op == PM_REMOVE) { + printf("usage: %s {-R --remove} [options] \n", myname); + printf("options:\n"); + printf(" -n, --nosave do not save .conf files\n"); + printf(" -v, --verbose be verbose\n"); + printf(" -r, --root set an alternative installation root\n"); + } else if(op == PM_UPGRADE) { + printf("usage: %s {-U --upgrade} [options] \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 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 set an alternative installation root\n"); + printf(" -o, --owns query the package that owns \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 \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 + * + * 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: */ -- cgit v1.2.3-24-g4f1b