Initial revision

This commit is contained in:
Judd Vinet 2005-03-15 01:51:43 +00:00
commit d04baabafa
83 changed files with 15755 additions and 0 deletions

340
COPYING Normal file
View File

@ -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.

268
ChangeLog Normal file
View File

@ -0,0 +1,268 @@
VERSION DESCRIPTION
-----------------------------------------------------------------------------
2.9.5 - bugfix: missing files after re-ordering packages wrt
deps with --upgrade
- added "Repository" line to -Si output
- patch from Tommi Rantala to fix trim() behaviour with
empty or whitespace-only strings
- fixed removal order when using -Rc or -Rs
2.9.4 - fixed a bug that was introduced from another bugfix :-/
2.9.3 - fixed a couple manpage typos
- added --ignore to -S operations, works just like IgnorePkg
- respect IgnorePkg list when pulling in dependencies
- numerous memleak fixes
- some code changes to improve customizability/branding
- Makefile fix for nonstandard lib search paths (Kevin Piche)
- fixed the leftover directories in /tmp
- speed improvement patches from Tommi Rantala
2.9.2 - bugfix for 2.9.1
2.9.1 - --refresh now only downloads fresh packages lists if they've
been updated (currently only works with FTP)
2.9 - Improved -Rs functionality -- pacman now tracks why a package
is installed: explicitly, or as a dependency for another
package. -Rs will only remove dependencies that were not
explicitly installed.
- Added compressed package size to sync DBs -- shows the total
size of packages before downloading
- Patch from Tommi Rantala:
- Allow --info and --list together in queries
- Patch from Kevin Piche:
- Use list_add_sorted() with -Sg
- Patch from Hegedus Marton Csaba:
- Better manpage compression
- Added checks for additional hyphens in package versions
- mktemp was failing if %pmo_root%/tmp was missing -- fixed
2.8.4 - Added updatesync script from Jason Chu
- Changed the pacman binary to be dynamically linked
- Included a pacman.static binary as well
- Added fakeroot checks when seeing if we're root
- Fixed makepkg to use 'tail -n 1' instead of 'tail -1'
- Added patch from Kevin Piche:
- Cleanup db_loadpkgs(), add list_add_sorted()
- Fixed a memory leak in db_find_conflicts()
2.8.3 - Fixed a little makepkg bug with bash 3.0
- Fixed resolvedeps to always prefer literals over provisios
- Added --config option to specify an alternate config file
- Added "Include" directive to include repositories from
config files (inspired by Michael Baehr's patch)
- Added patch from Jason Chu:
- Even smarter file-conflict checking
2.8.2 - Fixed a segfault bug in file-conflict checks
- Made --noconfirm actually work. Go me.
2.8.1 - Added a HoldPkg option in pacman.conf, for the more
exploratory users who run things like "pacman -R pacman". It
will ask for confirmation before removing any packages listed
in the HoldPkg list
- Added a --noconfirm switch for use with script automation
- Modified dependency resolution to prefer packages explicitly
requested on the cmdline instead of those pulled in by
resolvedeps(). Example, if neither "xorg" nor "xfree86" is
installed and "blackbox xfree86" is requested, "xfree86" will
be used instead of "xorg"
- Added patch from Jason Chu:
- Smarter file-conflict checking with symlinked paths and
with files that move from one package to another
2.8 - Bugfixes:
- #861: file:/// urls not handled properly with XferCommand
- #1003: set umask before scriptlet calls
- #1027: download problems with http urls using -U/-A
- #1044: segfaults when using -Rs
- #863: "missing post_remove" errors with some packages
- #875: detect low disk space properly
- #986: makepkg -e doesn't validate files
- #1010: add -j option to makepkg
- #1028: make pacman -Sp runnable as non-root
- added pre_install and pre_upgrade scriptlet support
- added an "Architecture" field in the package meta-data
- added patch from Aurelien Foret which improves performance
adding or removing packages
- added implementation of GNU's strverscmp function for better
portability
- added explicit unlink() calls when --force is used, which
prevents those nasty "Text file busy" errors when you
force-upgrade something like pacman or glibc.
2.7.9 - added the "force" option to packages, so --sysupgrade can
downgrade packages when it needs to
2.7.8 - added post_remove scriptlet support
- added -Qs option (bug #854)
- a provisio does not imply conflict, to make a provisio target
conflict with anything else that provides the same thing, you
can now do this by specifying the provisio target as both a
provides and a conflict, eg:
conflicts=('x-server')
provides=('x-server')
- cleaned up the download progress bar a bit
- added %o parameter to XferCommand so wget can resume properly
- fixed a segfault in downloadfiles() (bug #787)
- patches from Oliver Burnett-Hall
- gensync uses a better temp dir (bug #774)
- PKGDEST can be set in makepkg.conf (bug #783)
- patches from Aurelien Foret
- segfault fix, couple memory leaks
- more sanity checks in "provides" searches
- fixed a little display bug in the progress bar
- made -Qip look like -Qi
- -Sc now removes OLD packages from cache, use -Scc for all
2.7.7 - added an XferCommand directive that will make pacman use an
external download utility like wget
- added a license field to package meta-data
- add url support to -A and -U operations (download packages)
- -Ss now searches thru provides fields
- added --dbonly option to -R
2.7.6 - added --print-uris option
- fixed an http download bug (bug #667)
- fixed a segfault related to replaces/conflicts handling
2.7.5 - "replaces" packages were ignoring IgnorePkg in pacman.conf
- fixed another bug in conflict handling
- found an out-dated reference to /usr/abs, fixed
- added a --recursive option for package removal, which removes
all deps of a target that aren't required by other packages
2.7.4 - fixed a bug in conflict handling, where installing a
conflicting package would fail even if the new package
"provided" it
- if pacman sees a newer version of itself during an upgrade,
it will ask to install itself first, then be re-run to upgrade
the other packages.
- You can now use the --info option with --sync to display an
uninstalled package's dependency info.
- Added a sane umask before db writes
- buffer overflow fix (bug #442)
2.7.3 - makepkg not longer strips files with .exe or .dll extensions
- Added Aurelien's patch:
- proxy support (no authentication yet)
- HTTP/1.1 support
- an improved progress bar with transfer rates and ETA
- cleaned up warning output a bit
2.7.2 - Supressed "No such file" messages during stripping
- Removed extra newlines in /var/log/pacman.log
- Added a --noextract option to makepkg to skip source extraction
2.7.1 - Fixed a couple obscure segfaults
- LogFiles were logging incorrect dates - fixed
- Cleaned up md5sum output in makepkg -g
- Added (optional) colorized output messages to makepkg
- Renamed the "stable" repo to "release" in pacman.conf
- Renamed the "unofficial" repo to "extra" in pacman.conf
2.7 - Added build-time dependencies to makepkg (Jason Chu)
- Added md5sum integrity checking to packages in --sync
mode (Aurelien Foret)
- Memory leak fixes (Aurelien Foret)
- Added CARCH variable to makepkg.conf for use in PKGBUILDs
- Added LogFile option for direct-to-file logging
- Added -Qii handling to show modified config files
- Allow --sync targets to specify an explicit repository to
sync from (eg, pacman -S current/patch)
2.6.4 - Altered pacman_upgrade() to allow a package to replace itself
2.6.3 - A couple memory fixes in the new replaces code
2.6.2 - Fixed a memory cleanup bug
- Aurelien's patch:
- bug #159 implemented (for -S and -R)
- fixed a bug with pacman -Sg (pacman was browsing only one
db to get groups)
- fixed a bug with list_merge()
- fixed some MLK (in dumppkg() and with "-Qi --orphans")
- now "pacman -Sg" only displays groups (without content)
whereas "pacman -Sg target1 target2" displays groups
target1 and target2 with content
2.6.1 - Added http download support (Aurelien Foret)
- Improved makepkg's --builddeps behaviour when called via
makeworld
- makepkg's md5 validation now occurs before source extraction
- makepkg delays fakeroot entry until after option parsing
- Fixed an argument-passing bug in fakeroot
- Modified pacman's behaviour wrt provides -- it now allows
multiple packages to be installed, even if they provide the
same thing (they were treated as conflicts before)
2.6 - Added group handling, so one can run 'pacman -S kde' and
install all files from the KDE group
- Fixed a duplication bug in cascade package removal
- Added support for virtual provisions with "provides" tags
- When conflicts are encountered, pacman now offers the chance
to remove the conflicting packages (provides or literals)
- Added support for renamed/combined packages with a "replaces"
tag
- Added --nostrip option to makepkg
- Improved --search to list all packages from all repos when
a search term is omitted
- Added logging support through syslog()
- Added fakeroot support to makepkg (RomanK)
- Added MD5sum generation/validation to makepkg (RomanK)
- Fixed a progress bar bug (Aurelien Foret)
- Sorted makepkg's .FILELISTs (Aurelien Foret)
- Targets are now re-ordered w.r.t. dependencies when
using -A/-U
- Modified --search to work when called as -Sys
- Modified abs to use ABS_ROOT from /etc/abs/abs.conf (Aurelien)
- Other bug fixes
2.5.1 - Minor bug fixes
2.5 - Added an URL tag to package info
- Sped up package load times by about 500% by introducing
a .FILELIST into the package
- Renamed the install scriptlet from ._install to .INSTALL
- Added patch from Aurlien Foret:
- Better lock handling (RW and RO)
- Sorted package order in -Qi's dependency lists
- Added a DBPath option to pacman.conf
- Fixed memory leaks
- Added the --nodeps option to -S
2.4.1 - Fixed a bug in makepkg's option parsing
2.4 - Added getopt-style options to makeworld
- Added -w <destdir> to makepkg
- makeworld now properly handles packages with --builddeps
- Added patches from Aurelien Foret:
- Cascading package removals. -Rc will remove a package and
all packages that require it
- Support for getopt-style options in makepkg
- the REQUIREDBY field is now updated when a package is
removed with --nodeps, then re-installed.
- Avoids duplicate dependency checks with sync
- Added a "NoPassiveFtp" option in pacman.conf
- Improvements to the --query listings
2.3.2 - Added patches from Aurelien Foret:
- FTP resume feature
- removed the hit-^C-and-delete-the-downloading-file safety
- IgnorePkg option in pacman.conf
- FTPAGENT setting in makepkg.conf
- Added --cleancache option to makepkg
2.3.1 - Fixed the progress bar overflow
- Pacman does not ask "Are you sure" when you use --downloadonly
- Switched up a couple makepkg options to be more consistent
with pacman's options
- If you ^C out of a file download, the package will now be
removed from the cache directory
2.3 - The beginnings of source-side dependency resolution, makepkg
can now either A) download/install missing deps with pacman
-S; or B) find missing deps in the /usr/abs tree and
build/install them.
- Added a --nodeps option to makepkg
- Improved the --search output
2.2 - More bugfixes
- Added --downloadonly switch to --sync
2.1 - Lots of bugfixes
- Added support for multiple respositories
- Improved the config file layout
- Improved dependency resolution and sorting
2.0 - Added dependency functionality
- Completely new database format, similar to FreeBSD
- Better internal data structures
- Merged pacsync functionality into pacman
- Now uses libftp for all file retrieval (currently only ftp)
- Automatic dependency resolution, a la apt-get
- Moved config stuff from /etc/pacsync.conf to /etc/pacman.conf
- Much better backup file handling, now uses md5 hashes a la rpm
1.23 - Added install/upgrade/remove scripting control
1.22 - Some manpage typo fixes
- Added --root switch to pacsync
- Added --help and ability to specify a PKGBUILD to makepkg
- Switched default downloader to snarf
1.21 - Added better backup control -- upgrade/add and remove
do different things with the -n switch
1.2 - Added wildcard handling
- Added man pages for makepkg and pacsync
- Added the pacsync utility for remote file fetching/sync
1.1 - Fixed some string-handling bugs
- Added better handling of configuration files and the like.
If "file" is about to be removed, but it is designated to
backed up, then it will be copied to "file.save"
- Changed db_find_conflicts() to ignore directories
1.0 - Initial Release

288
README Normal file
View File

@ -0,0 +1,288 @@
==========================================================================
README:
Overview and internals of the ALPM library and the PACMAN frontend.
This document describes the state of the implementation before its CVS
import.
At this stage, the code is in pre-alpha state, but the design should not
change that much.
There's still need for some work to get the current code properly working.
The tag "ORE" was added in various places in the code, each time a point
remains unclear or is not yet implemented.
==========================================================================
ALPM library overview & internals
=================================
Here is a list of the main objects and files from the ALPM (i.e. Arch
Linux Package Management) library.
This document, whilst not exhaustive, also indicates some limitations
(on purpose, or sometimes due to its poor design) of the library at the
present time.
Note: there is one special file ("alpm.h") which is the public interface
that should be distributed and installed on systems with the library.
Only structures, data and functions declared within this file are made
available to the frontend.
Lots of structures are of an opaque type and their fields are only
accessible in read-only mode, through some clearly defined functions.
Note: several structures and functions have been renamed compared to
pacman 2.9 code.
This was done at first for the sake of naming scheme consistency, and
then primarily because of potential namespace conflicts between library
and frontend spaces.
Indeed, it is not possible to have two different functions with the same
name declared in both spaces.
To avoid such conflicts, some function names have been prepended with
"_alpm_".
In a general manner, public library functions are named
"alpm_<type>_<action>" (examples: alpm_trans_commit(),
alpm_lib_release(), alpm_pkg_getinfo(), ...).
Internal (and thus private) functions should be named "_alpm_XXX" for
instance (examples: _alpm_needbackup(), _alpm_runscriplet(), ...).
As of now, this scheme is only applied to most sensitive functions
(mainly the ones from util.c), which have generic names, and thus, which
are likely to be redefined in the frontend.
One can consider that the frontend should have the priority in function
names choice, and that it is up to the library to hide its symbols to
avoid conflicts with the frontend ones.
Finally, functions defined and used inside a single file should be
defined as "static".
[HANDLE] (see handle.c)
The "handle" object is the heart of the library. It is a global
structure available from almost all other objects (althought some very
low level objects should not be aware of the handle object, like chained
list, package or groups structures.
There is only one instance, created by the frontend upon
"alpm_lib_init()" call, and destroyed upon "alpm_lib_release()" call.
alpm_lib_init() is used to initialize library internals and to create
the handle object (handle != NULL).
Before its call, the library can't be used.
alpm_lib_release() just does the opposite (memory used by the library is
freed, and handle is set to NULL).
After its call, the library is no more available.
The aim of the handle is to provide a central placeholder for essential
library parameters (filesystem root, pointers to database objects,
configuration parameters, ...)
The handle also allows to register a log callback usable by the frontend
to catch all sort of notifications from the library.
The frontend can choose the level of verbosity (i.e. the mask), or can
simply choose to not use the log callback.
A friendly frontend should care at least for WARNING and ERROR
notifications.
Other notifications can safely be ignored and are mainly available for
troubleshooting purpose.
Last, but not least, the handle holds a _unique_ transaction object.
[TRANSACTION] (see trans.c, and also alpm.c)
The transaction sturcture permits easy manipulations of several package
at a time (i.e. adding, upgrade and removal operations).
A transaction can be initiatied with a type (ADD, UPGRADE or REMOVE),
and some flags (NODEPS, FORCE, CASCADE, ...).
Note: there can only be one type at a time: a transaction is either
created to add packages to the system, or either created to remove packages.
The frontend can't request for mixed operations: it has to run several
transactions, one at a time, in such a case.
The flags allow to tweak the library behaviour during its resolution.
Note, that some options of the handle can also modify the behavior of a
transaction (NOUPGRADE, IGNOREPKG, ...).
Note: once a transaction has been initiated, it is not possible anymore
to modify its type or its flags.
One can also add some targets to a transaction (alpm_trans_addtarget()).
These targets represent the list of packages to be handled.
Then, a transaction needs to be prepared (alpm_trans_prepare()). It
means that the various targets added, will be inspected and challenged
against the set of alreayd installed packages (dependency checkings,
Last, a callback is associated with each transaction. During the
transaction resolution, each time a new step is started or done (i.e
dependency or conflict checkings, package adding or removal, ...), the
callback is called, allowing the frontend to be aware of the progress of
the resolution. Can be useful to implement a progress bar.
[CONFIGURATION/OPTIONS] (see handle.c)
The library does not use any configuration file. The handle holds a
number of configuration options instead (IGNOREPKG, SYSLOG usage,
log file name, registered databases, ...).
It is up to the frontend to set the options of the library.
Options can be manipulated using calls to
alpm_set_option()/alpm_get_option().
Note: the file system root is a special option which can only be defined
when calling alpm_lib_init(). It can't be modified afterwards.
[CACHE] (see cache.c)
Compared to pacman 2.9, there is now one cache object connected to each
database object.
There are both a package and a group cache.
The cache is loaded only on demand (i.e the cache is loaded the first
time data from it should used).
Note: the cache of a database is always destroyed by the library after
an operation changing the database content (adding and/or removal of
packages).
Beware frontends ;)
[PACKAGE] (see package.c, and also db.c)
The package structure is using three new fields, namely: origin, data,
infolevel.
The purpose of these fields is to know some extra info about data stored
in package structures.
For instance, where is the package coming from (i.e origin)?
Was it loaded from a file or loaded from the cache?
If it's coming from a file, then the field data holds the full path and
name of the file, and infolevel is set to the highest possible value
(all package fields are reputed to be known).
Otherwise, if the package comes from a database, data is a pointer to
the database structure hosting the package, and infolevel is set
according to the db_read() infolevel parameter (it is possible using
db_read() to only read a part of the package datas).
Indeed, to reduce database access, all packages data requested by the
frontend are comming from the cache. As a consequence, the library needs
to know exactly the level of information about packages it holds, and
then decide if more data needs to be fetched from the database.
In file alpm.c, have a look at alpm_pkg_getinfo() function to get an
overview.
[ERRORS] (error.c)
The library provides a global variable pm_errno.
It aims at being to the library what errno is for C system calls.
Almost all public library functions are returning an integer value: 0
indicating success, whereas -1 would indicate a failure.
If -1 is returned, the variable pm_errno is set to a meaningful value
(not always yet, but it should improve ;).
Wise frontends should always care for these returned values.
Note: the helper function alpm_strerror() can also be used to translate
the error code into a more friendly sentence.
[LIST] (see list.c, and especially list wrappers in alpm.c)
It is a double chained list structure, use only for the internal needs
of the library.
A frontend should be free to use its own data structures to manipulate
packages.
For instance, consider a graphical frontend using the gtk toolkit (and
as a consequence the glib library). The frontend will make use of the
glib chained lists or trees.
As a consequence, the library only provides a simple and very small
interface to retrieve pointers to its internal data (see functions
alpm_list_first(), alpm_list_next() and alpm_list_getdata()), giving to
the frontend the responsibility to copy and store the data retrieved
from the library in its own data structures.
PACMAN frontend overview & internals
====================================
Here are some words about the frontend responsibilities.
The library can operate only a small set of well defined operations and
dumy operations.
High level features are left to the frontend ;)
For instance, during a sysupgrade, the library returns the whole list of
packages to be upgraded, without any care for its content.
The frontend can inspect the list and perhaps notice that "pacman"
itself has to be upgraded. In such a case, the frontend can choose to
perform a special action.
[MAIN] (see pacman.c)
Calls for alpm_lib_init(), and alpm_lib_release().
Read the configuration file, and parse command line arguments.
Based on the action requested, it initiates the appropriate transactions
(see pacman_add(), pacman_remove(), pacman_sync() in files add.c,
remove.c and sync.c).
[CONFIGURATION] (see conf.c)
The frontend is using a configuration file, usually "/etc/pacman.conf".
Part of these options are only usefull for the frontend only (mainly,
the download stuffs, and some options like HOLDPKG).
The rest is used to configure the library.
[ADD/UPGRADE/REMOVE/SYNC]
Nothing new here, excepted some reorganization.
The file pacman.c has been divided into several smaller files, namely
add.c, remove.c, sync.c and query.c, to hold the big parts: pacman_add,
pacman_remove, pacman_sync.
These 3 functions have been splitted too to ease the code reading.
[DONWLOAD] (see download.c)
The library is not providing download facilities. As a consequence, it
is up the the frontend to retrieve packages from Arch Linux servers.
To do so, pacman is linked against an improved version of libftp
supporting both http and ftp donwloads.
As a consequence, the frontend is repsonsible for the directory
/var/cache/pacman/pkgs.
One can consider that this cache is a facility provided by pacman.
Note: other frontends have to download packages by themselves too,
although the cache directory can be shared by several frontends.
[LIST] (see list.c)
Single chained list.
A minimalistic chained list implementation to store options from the
configuration file, and targets passed to pacman on the command line.
LIMITATIONS/BEHAVIOR CHANGES COMPARED TO PACMAN 2.9
===================================================
Excepted missing features still needing to be implemented, one can
notice the following limitations:
- When trying to add a package that conflicts with an already installed
one, pacman won't ask for removing the latter one prior to install the
former.
It will stop with an error code mentionning a conflict.
The library can handle only one transaction at a time, and as a consequence,
it is not easily possible to remove a conflicting package while holding
still the on-going transaction...
- ...

23
TODO Normal file
View File

@ -0,0 +1,23 @@
TODO:
- get ride of "ORE" tags.
- implement missing functionnalities (mainly pacman -S <pkg1> <pkg2>, and
packages replacement)
- pacman_deptest() is not implemented
- backport new functionnalities from pacman >= 2.9
- bring back the autoconf/automake stuff
- review how things are displayed in the frontend (normal display,
verbose mode, which usage for the library log callback?)
- review errors handling in the library (globalise pm_errno usage,
improve error meanings)
- library documentation (doxygen? man pages for public functions? ...)
- import libtar code into CVS too?

0
config.h Normal file
View File

407
doc/makepkg.8.in Normal file
View File

@ -0,0 +1,407 @@
.TH makepkg 8 "August 3, 2004" "makepkg #VERSION#" ""
.SH NAME
makepkg \- package build utility
.SH SYNOPSIS
\fBmakepkg [options]\fP
.SH DESCRIPTION
\fBmakepkg\fP will build packages for you. All it needs is
a build-capable linux platform, wget, and some build scripts. The advantage
to a script-based build is that you only really do the work once. Once you
have the build script for a package, you just need to run makepkg and it
will do the rest: download and validate source files, check dependencies,
configure the buildtime settings, build the package, install the package
into a temporary root, make customizations, generate meta-info, and package
the whole thing up for \fBpacman\fP to use.
\fBmakeworld\fP can be used to rebuild an entire package group or the
entire build tree. See \fBmakeworld --help\fP for syntax.
.SH BUILD PROCESS (or How To Build Your Own Packages)
Start in an isolated directory (ie, it's not used for anything other
than building this package). The build script should be called PKGBUILD
and it should bear resemblance to the example below.
\fBNOTE:\fP If you have a local copy of the Arch Build System (ABS) tree
on your computer, you can copy the PKGBUILD.proto file to your new package
build directory and edit it from there. To acquire/sync the ABS tree, use
the \fBabs\fP script included with pacman/makepkg.
.TP
.TP
.SH PKGBUILD Example:
.RS
.nf
pkgname=modutils
pkgver=2.4.25
pkgrel=1
pkgdesc="Utilities for inserting and removing modules from the linux kernel"
url="http://www.kernel.org"
backup=(etc/modules.conf)
makedepends=('bash' 'mawk')
depends=('glibc' 'zlib')
source=(ftp://ftp.kernel.org/pub/linux/utils/kernel/$pkgname/v2.4/$pkgname-$pkgver.tar.bz2 \\
modules.conf)
md5sums=('2c0cca3ef6330a187c6ef4fe41ecaa4d' \\
'35175bee593a7cc7d6205584a94d8625')
build() {
cd $startdir/src/$pkgname-$pkgver
./configure --prefix=/usr --enable-insmod-static
make || return 1
make prefix=$startdir/pkg/usr install
mv $startdir/pkg/usr/sbin $startdir/pkg
mkdir -p $startdir/pkg/etc
cp ../modules.conf $startdir/pkg/etc
}
.fi
.RE
As you can see, the setup is fairly simple. The first three lines define
the package name and version info. They also define the final package name
which will be of the form \fI$pkgname-$pkgver-$pkgrel.pkg.tar.gz\fP. The fourth
line provides a brief description of the package. These four lines should
be present in every PKGBUILD script.
The line with \fIbackup=\fP specifies files that should be treated specially
when removing or upgrading packages. See \fBHANDLING CONFIG FILES\fP in
the \fIpacman\fP manpage for more information on this.
Lines 7 and 8 list the dependencies for this package. The \fIdepends\fP array
specifies the run-time dependencies and \fImakedepends\fP specifies the build-time
dependencies. In order to run the package, \fIdepends\fP must be satisfied. To
build the package, \fBall\fP dependencies must be satisifed first. makepkg
will check this before attempting to build the package.
The \fIsource\fP array tells makepkg which files to download/extract before compiling
begins. The \fImd5sums\fP array provides md5sums for each of these files. These
are used to validate the integrity of the source files.
Once your PKGBUILD is created, you can run \fImakepkg\fP from the build directory.
makepkg will then check dependencies and look for the source files required to
build. If some are missing it will attempt to download them, provided there is
a fully-qualified URL in the \fIsource\fP array.
The sources are then extracted into a directory called ./src and
the \fIbuild\fP function is called. This is where all package configuration,
building, and installing should be done. Any customization will likely take
place here.
After a package is built, the \fIbuild\fP function must install the package
files into a special package root, which can be referenced by \fB$startdir/pkg\fP
in the \fIbuild\fP function. The typical way to do this is one of the following:
.RS
.nf
make DESTDIR=$startdir/pkg install
or
make prefix=$startdir/pkg/usr install
.fi
.RE
Notice that the "/usr" portion should be present with "prefix", but not "DESTDIR".
"DESTDIR" is the favorable option to use, but not all Makefiles support it. Use
"prefix" only when "DESTDIR" is unavailable.
Once the package is successfully installed into the package root, \fImakepkg\fP
will remove some directories (as per Arch Linux package guidelines; if you use
this elsewhere, feel free to change it) like /usr/doc and /usr/info. It will
then strip debugging info from libraries and binaries and generate a meta-info
file. Finally, it will compress everything into a .pkg.tar.gz file and leave it
in the directory you ran \fBmakepkg\fP from.
At this point you should have a package file in the current directory, named
something like name-version-release.pkg.tar.gz. Done!
.SH Install/Upgrade/Remove Scripting
Pacman has the ability to store and execute a package-specific script when it
installs, removes, or upgrades a package. This allows a package to "configure
itself" after installation and do the opposite right before it is removed.
The exact time the script is run varies with each operation:
.TP
.B pre_install
script is run right before files are extracted.
.TP
.B post_install
script is run right after files are extracted.
.TP
.B pre_upgrade
script is run right before files are extracted.
.TP
.B post_upgrade
script is run after files are extracted.
.TP
.B pre_remove
script is run right before files are removed.
.TP
.B post_remove
script is run right after files are removed.
.RE
To use this feature, just create a file (eg, pkgname.install) and put it in
the same directory as the PKGBUILD script. Then use the \fIinstall\fP directive:
.RS
.nf
install=pkgname.install
.fi
.RE
The install script does not need to be specified in the \fIsource\fP array.
.TP
.TP
.SH Install scripts must follow this format:
.RS
.nf
# arg 1: the new package version
pre_install() {
#
# do pre-install stuff here
#
/bin/true
}
# arg 1: the new package version
post_install() {
#
# do post-install stuff here
#
/bin/true
}
# arg 1: the new package version
# arg 2: the old package version
pre_upgrade() {
#
# do pre-upgrade stuff here
#
/bin/true
}
# arg 1: the new package version
# arg 2: the old package version
post_upgrade() {
#
# do post-upgrade stuff here
#
/bin/true
}
# arg 1: the old package version
pre_remove() {
#
# do pre-remove stuff here
#
/bin/true
}
# arg 1: the old package version
post_remove() {
#
# do post-remove stuff here
#
/bin/true
}
op=$1
shift
$op $*
.fi
.RE
This template is also available in your ABS tree (/var/abs/install.proto).
.SH PKGBUILD Directives
.TP
.B pkgname
The name of the package. This has be a unix-friendly name as it will be
used in the package filename.
.TP
.B pkgver
This is the version of the software as released from the author (eg, 2.7.1).
.TP
.B pkgrel
This is the release number specific to Arch Linux packages.
.TP
.B pkgdesc
This should be a brief description of the package and its functionality.
.TP
.B force
This is used to force the package to be upgraded by \fB--sysupgrade\fP, even
if its an older version.
.TP
.B url
This field contains an optional URL that is associated with the piece of software
being packaged. This is typically the project's website.
.TP
.B license
Sets the license type (eg, "GPL", "BSD", "NON-FREE"). (\fBNote\fP: This
option is still in development and may change in the future)
.TP
.B install
Specifies a special install script that is to be included in the package.
This file should reside in the same directory as the PKGBUILD, and will be
copied into the package by makepkg. It does not need to be included in the
\fIsource\fP array. (eg, install=modutils.install)
.TP
.B source \fI(array)\fP
The \fIsource\fP line is an array of source files required to build the
package. Source files must reside in the same directory as the PKGBUILD
file, unless they have a fully-qualified URL. Then if the source file
does not already exist in /var/cache/pacman/src, the file is downloaded
by wget.
.TP
.B md5sums \fI(array)\fP
If this field is present, it should contain an MD5 hash for every source file
specified in the \fIsource\fP array (in the same order). makepkg will use
this to verify source file integrity during subsequent builds. To easily
generate md5sums, first build using the PKGBUILD then run
\fBmakepkg -g >>PKGBILD\fP. Then you can edit the PKGBUILD and move the
\fImd5sums\fP line from the bottom to an appropriate location.
.TP
.B groups \fI(array)\fP
This is an array of symbolic names that represent groups of packages, allowing
you to install multiple packages by requesting a single target. For example,
one could install all KDE packages by installing the 'kde' group.
.TP
.B backup \fI(array)\fP
A space-delimited array of filenames (without a preceding slash). The
\fIbackup\fP line will be propagated to the package meta-info file for
pacman. This will designate all files listed there to be backed up if this
package is ever removed from a system. See \fBHANDLING CONFIG FILES\fP in
the \fIpacman\fP manpage for more information.
.TP
.B depends \fI(array)\fP
An array of packages that this package depends on to build and run. Packages
in this list should be surrounded with single quotes and contain at least the
package name. They can also include a version requirement of the form
\fBname<>version\fP, where <> is one of these three comparisons: \fB>=\fP
(greater than equal to), \fB<=\fP (less than or equal to), or \fB=\fP (equal to).
See the PKGBUILD example above for an example of the \fIdepends\fP directive.
.TP
.B makedepends \fI(array)\fP
An array of packages that this package depends on to build (ie, not required
to run). Packages in this list should follow the same format as \fIdepends\fP.
.TP
.B conflicts \fI(array)\fP
An array of packages that will conflict with this package (ie, they cannot both
be installed at the same time). This directive follows the same format as
\fIdepends\fP except you cannot specify versions here, only package names.
.TP
.B provides \fI(array)\fP
An array of "virtual provisions" that this package provides. This allows a package
to provide dependency names other than it's own package name. For example, the
kernel-scsi and kernel-ide packages can each provide 'kernel' which allows packages
to simply depend on 'kernel' rather than "kernel-scsi OR kernel-ide OR ..."
.TP
.B replaces \fI(array)\fP
This is an array of packages that this package should replace, and can be used to handle
renamed/combined packages. For example, if the kernel package gets renamed
to kernel-ide, then subsequent 'pacman -Syu' calls will not pick up the upgrade, due
to the differing package names. \fIreplaces\fP handles this.
.SH MAKEPKG OPTIONS
.TP
.B "\-b, \-\-builddeps"
Build missing dependencies from source. When makepkg finds missing build-time or
run-time dependencies, it will look for the dependencies' PKGBUILD files under
$ABSROOT (set in your /etc/makepkg.conf). If it finds them it will
run another copy of makepkg to build and install the missing dependencies.
The child makepkg calls will be made with the \fB-b\fP and \fB-i\fP options.
.TP
.B "\-c, \-\-clean"
Clean up leftover work files/directories after a successful build.
.TP
.B "\-C, \-\-cleancache"
Removes all source files from the cache directory to free up diskspace.
.TP
.B "\-d, \-\-nodeps"
Do not perform any dependency checks. This will let you override/ignore any
dependencies required. There's a good chance this option will break the build
process if all of the dependencies aren't installed.
.TP
.B "\-f, \-\-force"
\fBmakepkg\fP will not build a package if a \fIpkgname-pkgver-pkgrel.pkg.tar.gz\fP
file already exists in the build directory. You can override this behaviour with
the \fB--force\fP switch.
.TP
.B "\-g, \-\-genmd5"
Download all source files (if required) and use \fImd5sum\fP to generate md5 hashes
for each of them. You can then redirect the output into your PKGBUILD for source
validation (makepkg -g >>PKGBUILD).
.TP
.B "\-h, \-\-help"
Output syntax and commandline options.
.TP
.B "\-i, \-\-install"
Install/Upgrade the package after a successful build.
.TP
.B "\-j <jobs>"
Sets MAKEFLAGS="-j<jobs>" before building the package. This is useful for overriding
the MAKEFLAGS setting in /etc/makepkg.conf.
.TP
.B "\-m, \-\-nocolor"
Disable color in output messages
.TP
.B "\-n, \-\-nostrip"
Do not strip binaries and libraries.
.TP
.B "\-o, \-\-nobuild"
Download and extract files only, do not build.
.TP
.B "\-p <buildscript>"
Read the package script \fI<buildscript>\fP instead of the default (\fIPKGBUILD\fP).
.TP
.B "\-r, \-\-rmdeps"
Upon successful build, remove any dependencies installed by makepkg/pacman during
dependency auto-resolution (using \fB-b\fP or \fB-s\fP).
.TP
.B "\-s, \-\-syncdeps"
Install missing dependencies using pacman. When makepkg finds missing build-time
or run-time dependencies, it will run pacman to try and resolve them. If successful,
pacman will download the missing packages from a package repository and
install them for you.
.TP
.B "\-w <destdir>"
Write the resulting package file to the directory \fI<destdir>\fP instead of the
current working directory.
.SH CONFIGURATION
Configuration options are stored in \fI/etc/makepkg.conf\fP. This file is parsed
as a bash script, so you can export any special compiler flags you wish
to use. This is helpful for building for different architectures, or with
different optimizations.
\fBNOTE:\fP This does not guarantee that all package Makefiles will use
your exported variables. Some of them are flaky...
.SH SEE ALSO
\fBpacman\fP is the package manager that uses packages built by makepkg.
See the Arch Linux Documentation for package-building guidelines if you wish
to contribute packages to the Arch Linux project.
.SH AUTHOR
.nf
Judd Vinet <jvinet@zeroflux.org>
.fi

312
doc/pacman.8.in Normal file
View File

@ -0,0 +1,312 @@
.TH pacman 8 "September 17, 2004" "pacman #VERSION#" ""
.SH NAME
pacman \- package manager utility
.SH SYNOPSIS
\fBpacman <operation> [options] <package> [package] ...\fP
.SH DESCRIPTION
\fBpacman\fP is a \fIpackage management\fP utility that tracks installed
packages on a linux system. It has simple dependency support and the ability
to connect to a remote ftp server and automatically upgrade packages on
the local system. pacman package are \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 "\-F, \-\-freshen"
This is like --upgrade except that, unlike --upgrade, this will only
upgrade packages that are already installed on your system.
.TP
.B "\-Q, \-\-query"
Query the package database. This operation allows you to
view installed packages and their files, as well as meta-info
about individual packages (dependencies, conflicts, install date,
build date, size). This can be run against the local package
database or can be used on individual .tar.gz packages. See
\fBQUERY OPTIONS\fP below.
.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. Most configuration files will be saved with a
\fI.pacsave\fP extension unless the \fB--nosave\fP option was
used.
.TP
.B "\-S, \-\-sync"
Synchronize packages. With this function you can install packages
directly from the ftp servers, complete with all dependencies required
to run the packages. For example, \fBpacman -S qt\fP will download
qt and all the packages it depends on and install them. You could also use
\fBpacman -Su\fP to upgrade all packages that are out of date (see below).
.TP
.B "\-U, \-\-upgrade"
Upgrade a package. This is essentially a "remove-then-add"
process. See \fBHANDLING CONFIG FILES\fP for an explanation
on how pacman takes care of config files.
.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 OPTIONS
.TP
.B "\-d, \-\-nodeps"
Skips all dependency checks. Normally, pacman will always check
a package's dependency fields to ensure that all dependencies are
installed and there are no package conflicts in the system. This
switch disables these checks.
.TP
.B "\-f, \-\-force"
Bypass file conflict checks, 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, ideally 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.
.TP
.B "\-v, \-\-verbose"
Output more status and error messages.
.TP
.B "\-\-config <path>"
Specify an alternate configuration file.
.TP
.B "\-\-noconfirm"
Bypass any and all "Are you sure?" messages. It's not a good to do this
unless you want to run pacman from a script.
.SH SYNC OPTIONS
.TP
.B "\-c, \-\-clean"
Remove old packages from the cache. When pacman downloads packages,
it saves them in \fI/var/cache/pacman/pkg\fP. If you need to free up
diskspace, you can remove these packages by using the --clean option.
Using one --clean (or -c) switch will only remove \fIold\fP packages.
Use it twice to remove \fIall\fP packages from the cache.
.TP
.B "\-g, \-\-groups"
Display all the members for each package group specified. If no group
names are provided, all groups will be listed.
.TP
.B "\-i, \-\-info"
Display dependency information for a given package. This will search
through all repositories for a matching package and display the
dependencies, conflicts, etc.
.TP
.B "\-l, \-\-list"
List all files in the specified repositories. Multiple repositories can
be specified on the command line.
.TP
.B "\-p, \-\-print-uris"
Print out URIs for each specified package and its dependencies. These
can be piped to a file and downloaded at a later time, using a program
like wget.
.TP
.B "\-s, \-\-search <string>"
This will search each package in the package list for names or descriptions
that contains <string>.
.TP
.B "\-u, \-\-sysupgrade"
Upgrades all packages that are out of date. pacman will examine every
package installed on the system, and if a newer package exists on the
server it will upgrade. pacman will present a report of all packages
it wants to upgrade and will not proceed without user confirmation.
Dependencies are automatically resolved at this level and will be
installed/upgraded if necessary.
.TP
.B "\-w, \-\-downloadonly"
Retrieve all packages from the server, but do not install/upgrade anything.
.TP
.B "\-y, \-\-refresh"
Download a fresh copy of the master package list from the ftp server
defined in \fI/etc/pacman.conf\fP. This should typically be used each
time you use \fB--sysupgrade\fP.
.TP
.B "\-\-ignore <pkg>"
This option functions exactly the same as the \fBIgnorePkg\fP configuration
directive. Sometimes it can be handy to skip some package updates without
having to edit \fIpacman.conf\fP each time.
.SH REMOVE OPTIONS
.TP
.B "\-c, \-\-cascade"
Remove all target packages, as well as all packages that depend on one
or more target packages. This operation is recursive.
.TP
.B "\-k, \-\-keep"
Removes the database entry only. Leaves all files in place.
.TP
.B "\-n, \-\-nosave"
Instructs pacman to ignore file backup designations. Normally, when
a file is about to be \fIremoved\fP from the system the database is first
checked to see if the file should be renamed to a .pacsave extension. If
\fB--nosave\fP is used, these designations are ignored and the files are
removed.
.TP
.B "\-s, \-\-recursive"
For each target specified, remove it and all its dependencies, provided
that (A) they are not required by other packages; and (B) they were not
explicitly installed by the user.
This option is analagous to a backwards --sync operation.
.SH QUERY OPTIONS
.TP
.B "\-e, \-\-orphans"
List all packages that were explicitly installed (ie, not pulled in
as a dependency by other packages) and are not required by any other
packages.
.TP
.B "\-g, \-\-groups"
Display all groups that a specified package is part of. If no package
names are provided, all groups and members will be listed.
.TP
.B "\-i, \-\-info"
Display information on a given package. If it is used with the \fB-p\fP
option then the .PKGINFO file will be printed.
.TP
.B "\-l, \-\-list"
List all files owned by <package>. Multiple packages can be specified on
the command line.
.TP
.B "\-o, \-\-owns <file>"
Search for the package that owns <file>.
.TP
.B "\-p, \-\-file"
Tells pacman that the package supplied on the command line is a
file, not an entry in the database. Pacman will decompress the
file and query it. This is useful with \fB--info\fP and \fB--list\fP.
.TP
.B "\-s, \-\-search <string>"
This will search each locally-installed package for names or descriptions
that contains <string>.
.SH HANDLING CONFIG FILES
pacman uses the same logic as rpm to determine action against files
that are designated to be backed up. During an upgrade, it uses 3
md5 hashes for each backup file to determine the required action:
one for the original file installed, one for the new file that's about
to be installed, and one for the actual file existing on the filesystem.
After comparing these 3 hashes, the follow scenarios can result:
.TP
original=\fBX\fP, current=\fBX\fP, new=\fBX\fP
All three files are the same, so we win either way. Install the new file.
.TP
original=\fBX\fP, current=\fBX\fP, new=\fBY\fP
The current file is un-altered from the original but the new one is
different. Since the user did not ever modify the file, and the new
one may contain improvements/bugfixes, we install the new file.
.TP
original=\fBX\fP, current=\fBY\fP, new=\fBX\fP
Both package versions contain the exact same file, but the one
on the filesystem has been modified since. In this case, we leave
the current file in place.
.TP
original=\fBX\fP, current=\fBY\fP, new=\fBY\fP
The new one is identical to the current one. Win win. Install the new file.
.TP
original=\fBX\fP, current=\fBY\fP, new=\fBZ\fP
All three files are different. So we install the new file, but back up the
old one to a .pacsave extension. This way the user can move the old configuration
file back into place if he wishes.
.SH CONFIGURATION
pacman will attempt to read \fI/etc/pacman.conf\fP each time it is invoked. This
configuration file is divided into sections or \fIrepositories\fP. Each section
defines a package repository that pacman can use when searching for packages in
--sync mode. The exception to this is the \fIoptions\fP section, which defines
global options.
.TP
.SH Example:
.RS
.nf
[options]
NoUpgrade = etc/passwd etc/group etc/shadow
NoUpgrade = etc/fstab
Include = /etc/pacman.d/current
[custom]
Server = file:///home/pkgs
.fi
.RE
.SH CONFIG: OPTIONS
.TP
.B "DBPath = path/to/db/dir"
Overrides the default location of the toplevel database directory. The default is
\fIvar/lib/pacman\fP.
.TP
.B "HoldPkg = <package> [package] ..."
If a user tries to \fB--remove\fP a package that's listed in HoldPkg, pacman
will ask for confirmation before proceeding.
.TP
.B "IgnorePkg = <package> [package] ..."
Instructs pacman to ignore any upgrades for this package when performing a
\fB--sysupgrade\fP.
.TP
.B "Include = <path>"
Include another config file. This config file can include repositories or
general configuration options.
.TP
.B "ProxyServer = <host|ip>[:port]"
If set, pacman will use this proxy server for all ftp/http transfers.
.TP
.B "XferCommand = /path/to/command %u"
If set, pacman will use this external program to download all remote files.
All instances of \fB%u\fP will be replaced with the URL to be downloaded. If
present, instances of \fB%o\fP will be replaced with the local filename, plus a
".part" extension, which allows programs like wget to do file resumes properly.
This option is useful for users who experience problems with pacman's built-in http/ftp
support, or need the more advanced proxy support that comes with utilities like
wget.
.TP
.B "NoPassiveFtp"
Disables passive ftp connections when downloading packages. (aka Active Mode)
.TP
.B "NoUpgrade = <file> [file] ..."
All files listed with a \fBNoUpgrade\fP directive will never be touched during a package
install/upgrade. \fINote:\fP do not include the leading slash when specifying files.
.TP
.B "UseSyslog"
Log action messages through syslog(). This will insert pacman log entries into your
/var/log/messages or equivalent.
.TP
.B "LogFile = /path/to/file"
Log actions directly to a file, usually /var/log/pacman.log.
.SH CONFIG: REPOSITORIES
Each repository section defines a section name and at least one location where the packages
can be found. The section name is defined by the string within square brackets (eg, the two
above are 'current' and 'custom'). Locations are defined with the \fIServer\fP directive and
follow a URL naming structure. Currently only ftp is supported for remote servers. If you
want to use a local directory, you can specify the full path with a 'file://' prefix, as
shown above.
.SH USING YOUR OWN REPOSITORY
Let's say you have a bunch of custom packages in \fI/home/pkgs\fP and their respective PKGBUILD
files are all in \fI/var/abs/local\fP. All you need to do is generate a compressed package database
in the \fI/home/pkgs\fP directory so pacman can find it when run with --refresh.
.RS
.nf
# gensync /var/abs/local /home/pkgs/custom.db.tar.gz
.fi
.RE
The above command will read all PKGBUILD files in /var/abs/local and generate a compressed
database called /home/pkgs/custom.db.tar.gz. Note that the database must be of the form
\fI{treename}.db.tar.gz\fP, where {treename} is the name of the section defined in the
configuration file.
That's it! Now configure your \fIcustom\fP section in the configuration file as shown in the
config example above. Pacman will now use your package repository. If you add new packages to
the repository, remember to re-generate the database and use pacman's --refresh option.
.SH SEE ALSO
\fBmakepkg\fP is the package-building tool that comes with pacman.
.SH AUTHOR
.nf
Judd Vinet <jvinet@zeroflux.org>
.fi

36
etc/makepkg.conf Normal file
View File

@ -0,0 +1,36 @@
#
# /etc/makepkg.conf
#
# The FTP/HTTP download utility that makepkg should use to acquire sources
export FTPAGENT="/usr/bin/wget --continue --passive-ftp --tries=3 --waitretry=3"
#export FTPAGENT="/usr/bin/snarf"
#export FTPAGENT="/usr/bin/lftpget -c"
export CARCH="i686"
export CHOST="i686-pc-linux-gnu"
# Pentium Pro/Pentium II/Pentium III+/Pentium 4/Athlon exclusive (binaries
# will use the P6 instruction set and only run on P6+ systems)
export CFLAGS="-march=i686 -O2 -pipe -Wl,-O1"
export CXXFLAGS="-march=i686 -O2 -pipe -Wl,-O1"
# Pentium Pro/Pentium II/Pentium III+/Pentium 4/Athlon optimized (but binaries
# will run on any x86 system)
#export CFLAGS="-mcpu=i686 -O2 -pipe"
#export CXXFLAGS="-mcpu=i686 -O2 -pipe"
# SMP Systems
#export MAKEFLAGS="-j 2"
# Enable fakeroot for building packages as a non-root user
export USE_FAKEROOT="y"
# Enable colorized output messages
export USE_COLOR="n"
# Specify a fixed directory where all packages will be placed
#export PKGDEST=/home/packages
# If you want your name to show up in the packages you build, set this.
#export PACKAGER="John Doe <john@doe.com>"

53
etc/pacman.conf Normal file
View File

@ -0,0 +1,53 @@
#
# /etc/pacman.conf
#
# NOTE: If you find a mirror that is geographically close to you, please
# move it to the top of the server list, so pacman will choose it
# first.
#
# To re-sort your mirror lists by ping/traceroute results, use the
# /usr/bin/sortmirrors.pl script. It requires the "netselect" package.
#
# # sortmirrors.pl </etc/pacman.conf >pacman.conf.new
#
# See the pacman manpage for option directives
#
# GENERAL OPTIONS
#
[options]
LogFile = /var/log/pacman.log
NoUpgrade = etc/passwd etc/group etc/shadow etc/sudoers
NoUpgrade = etc/fstab etc/raidtab etc/ld.so.conf
NoUpgrade = etc/rc.conf etc/rc.local
NoUpgrade = etc/modprobe.conf etc/modules.conf
NoUpgrade = etc/lilo.conf boot/grub/menu.lst
HoldPkg = pacman glibc
#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u
#
# REPOSITORIES
# - can be defined here or included from another file
# - pacman will search repositories in the order defined here.
# - local/custom mirrors can be added here or in separate files
#
#[testing]
#Server = ftp://ftp.archlinux.org/testing/os/i686
[current]
# Add your preferred servers here, they will be used first
Include = /etc/pacman.d/current
[extra]
# Add your preferred servers here, they will be used first
Include = /etc/pacman.d/extra
#Include = /etc/pacman.d/unstable
# An example of a custom package repository. See the pacman manpage for
# tips on creating your own repositories.
#[custom]
#Server = file:///home/custompkgs

39
lib/libalpm/Makefile Normal file
View File

@ -0,0 +1,39 @@
CXX=gcc
CFLAGS=-g -Wall -pedantic -D_GNU_SOURCE -I. -I../..
AR=ar rc
RAN=ranlib
OBJS=md5driver.o \
md5.o \
util.o \
list.o \
log.o \
error.o \
package.o \
group.o \
db.o \
cache.o \
deps.o \
provide.o \
rpmvercmp.o \
backup.o \
trans.o \
add.o \
remove.o \
sync.o \
handle.o \
alpm.o
all: libalpm.a
%.o: %.c %.h
$(CXX) -c $(CFLAGS) -o $@ $<
libalpm.a: $(OBJS) alpm.h
$(AR) $@ $(OBJS)
$(RAN) $@
clean:
rm -f *.o *~ core
rm -f libalpm.a

580
lib/libalpm/add.c Normal file
View File

@ -0,0 +1,580 @@
/*
* add.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
#include <zlib.h>
#include <libtar.h>
/* pacman */
#include "util.h"
#include "error.h"
#include "list.h"
#include "cache.h"
#include "rpmvercmp.h"
#include "md5.h"
#include "log.h"
#include "backup.h"
#include "package.h"
#include "db.h"
#include "provide.h"
#include "trans.h"
#include "deps.h"
#include "add.h"
#include "remove.h"
#include "handle.h"
extern pmhandle_t *handle;
int add_loadtarget(pmdb_t *db, pmtrans_t *trans, char *name)
{
pmpkg_t *info, *dummy;
PMList *j;
ASSERT(db != NULL, PM_RET_ERR(PM_ERR_DB_NULL, -1));
ASSERT(trans != NULL, PM_RET_ERR(PM_ERR_TRANS_NULL, -1));
ASSERT(name != NULL, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
/* ORE
load_pkg should be done only if pkg has to be added to the transaction */
_alpm_log(PM_LOG_FLOW2, "reading %s...", name);
info = pkg_load(name);
if(info == NULL) {
/* pm_errno is already set by pkg_load() */
return(-1);
}
/* no additional hyphens in version strings */
if(strchr(info->version, '-') != strrchr(info->version, '-')) {
FREEPKG(info);
pm_errno = PM_ERR_INVALID_NAME;
return(-1);
}
dummy = db_get_pkgfromcache(db, info->name);
/* only freshen this package if it is already installed and at a lesser version */
if(trans->flags & PM_TRANS_FLAG_FRESHEN) {
if(dummy == NULL || rpmvercmp(dummy->version, info->version) >= 0) {
FREEPKG(info);
PM_RET_ERR(PM_ERR_PKG_CANT_FRESH, -1);
}
}
/* only install this package if it is not already installed */
if(trans->type != PM_TRANS_TYPE_UPGRADE) {
if(dummy) {
FREEPKG(info);
PM_RET_ERR(PM_ERR_PKG_INSTALLED, -1);
}
}
/* check if an older version of said package is already in transaction packages.
* if so, replace it in the list */
/* ORE
we'd better do it before load_pkg. */
for(j = trans->packages; j; j = j->next) {
pmpkg_t *pkg = j->data;
if(strcmp(pkg->name, info->name) != 0) {
if(rpmvercmp(pkg->version, info->version) < 0) {
_alpm_log(PM_LOG_WARNING, "replacing older version of %s in target list", pkg->name);
FREEPKG(j->data);
j->data = info;
}
}
}
/* add the package to the transaction */
trans->packages = pm_list_add(trans->packages, info);
return(0);
}
int add_prepare(pmdb_t *db, pmtrans_t *trans, PMList **data)
{
PMList *lp;
*data = NULL;
ASSERT(db != NULL, PM_RET_ERR(PM_ERR_DB_NULL, -1));
ASSERT(trans != NULL, PM_RET_ERR(PM_ERR_TRANS_NULL, -1));
ASSERT(data != NULL, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
/* ORE ???
No need to check deps if pacman_add was called during a sync:
it is already done in pacman_sync */
/* Check dependencies
*/
if(!(trans->flags & PM_TRANS_FLAG_NODEPS)) {
PMList *j;
TRANS_CB(trans, PM_TRANS_CB_DEPS_START, NULL, NULL);
lp = checkdeps(db, trans->type, trans->packages);
if(lp != NULL) {
int errorout = 0;
/* look for unsatisfied dependencies */
_alpm_log(PM_LOG_FLOW2, "looking for unsatisfied dependencies...");
for(j = lp; j; j = j->next) {
pmdepmissing_t* miss = j->data;
if(miss->type == PM_DEP_DEPEND || miss->type == PM_DEP_REQUIRED) {
if(!errorout) {
errorout = 1;
}
if((miss = (pmdepmissing_t *)malloc(sizeof(pmdepmissing_t))) == NULL) {
FREELIST(lp);
/* ORE, needed or not ?
FREELIST(*data);*/
PM_RET_ERR(PM_ERR_MEMORY, -1);
}
*miss = *(pmdepmissing_t*)j->data;
*data = pm_list_add(*data, miss);
}
}
if(errorout) {
FREELIST(lp);
PM_RET_ERR(PM_ERR_UNSATISFIED_DEPS, -1);
}
/* no unsatisfied deps, so look for conflicts */
_alpm_log(PM_LOG_FLOW2, "looking for conflicts...");
for(j = lp; j; j = j->next) {
pmdepmissing_t* miss = (pmdepmissing_t *)j->data;
if(miss->type == PM_DEP_CONFLICT) {
if(!errorout) {
errorout = 1;
}
MALLOC(miss, sizeof(pmdepmissing_t));
*miss = *(pmdepmissing_t*)j->data;
*data = pm_list_add(*data, miss);
}
}
if(errorout) {
FREELIST(lp);
PM_RET_ERR(PM_ERR_CONFLICTING_DEPS, -1);
}
FREELIST(lp);
}
/* re-order w.r.t. dependencies */
_alpm_log(PM_LOG_FLOW2, "sorting by dependencies...");
lp = sortbydeps(trans->packages);
/* free the old alltargs */
for(j = trans->packages; j; j = j->next) {
j->data = NULL;
}
FREELIST(trans->packages);
trans->packages = lp;
TRANS_CB(trans, PM_TRANS_CB_DEPS_DONE, NULL, NULL);
}
/* Check for file conflicts
*/
if(!(trans->flags & PM_TRANS_FLAG_FORCE)) {
TRANS_CB(trans, PM_TRANS_CB_CONFLICTS_START, NULL, NULL);
lp = db_find_conflicts(db, trans->packages, handle->root);
if(lp != NULL) {
*data = lp;
PM_RET_ERR(PM_ERR_FILE_CONFLICTS, -1);
}
TRANS_CB(trans, PM_TRANS_CB_CONFLICTS_DONE, NULL, NULL);
}
return(0);
}
int add_commit(pmdb_t *db, pmtrans_t *trans)
{
int i, ret = 0, errors = 0;
TAR *tar = NULL;
char expath[PATH_MAX];
time_t t;
pmpkg_t *info = NULL;
PMList *targ, *lp;
ASSERT(db != NULL, PM_RET_ERR(PM_ERR_DB_NULL, -1));
ASSERT(trans != NULL, PM_RET_ERR(PM_ERR_TRANS_NULL, -1));
if(trans->packages == NULL) {
return(0);
}
for(targ = trans->packages; targ; targ = targ->next) {
tartype_t gztype = {
(openfunc_t)_alpm_gzopen_frontend,
(closefunc_t)gzclose,
(readfunc_t)gzread,
(writefunc_t)gzwrite
};
unsigned short pmo_upgrade = (trans->type == PM_TRANS_TYPE_UPGRADE) ? 1 : 0;
char pm_install[PATH_MAX];
pmpkg_t *oldpkg = NULL;
info = (pmpkg_t *)targ->data;
errors = 0;
/* see if this is an upgrade. if so, remove the old package first */
if(pmo_upgrade) {
if(pkg_isin(info, db_get_pkgcache(db))) {
TRANS_CB(trans, PM_TRANS_CB_UPGRADE_START, info, NULL);
/* we'll need the full record for backup checks later */
if((oldpkg = db_scan(db, info->name, INFRQ_ALL)) != NULL) {
pmtrans_t *tr;
_alpm_log(PM_LOG_FLOW2, "removing old package first...\n");
/* ORE
set flags to something, but what (nodeps?) ??? */
tr = trans_new();
if(tr == NULL) {
PM_RET_ERR(PM_ERR_TRANS_ABORT, -1);
}
if(trans_init(tr, PM_TRANS_TYPE_UPGRADE, 0, NULL) == -1) {
FREETRANS(tr);
PM_RET_ERR(PM_ERR_TRANS_ABORT, -1);
}
if(remove_loadtarget(db, tr, info->name) == -1) {
FREETRANS(tr);
PM_RET_ERR(PM_ERR_TRANS_ABORT, -1);
}
if(remove_commit(db, tr) == -1) {
FREETRANS(tr);
PM_RET_ERR(PM_ERR_TRANS_ABORT, -1);
}
FREETRANS(tr);
}
} else {
/* no previous package version is installed, so this is actually just an
* install
*/
pmo_upgrade = 0;
}
}
if(!pmo_upgrade) {
TRANS_CB(trans, PM_TRANS_CB_ADD_START, info, NULL);
}
/* Add the package to the database */
t = time(NULL);
/* Update the requiredby field by scaning the whole database
* looking for packages depending on the package to add */
for(lp = db_get_pkgcache(db); lp; lp = lp->next) {
pmpkg_t *tmpp = NULL;
PMList *tmppm = NULL;
tmpp = db_scan(db, ((pmpkg_t *)lp->data)->name, INFRQ_DEPENDS);
if(tmpp == NULL) {
continue;
}
for(tmppm = tmpp->depends; tmppm; tmppm = tmppm->next) {
pmdepend_t depend;
splitdep(tmppm->data, &depend);
if(tmppm->data && !strcmp(depend.name, info->name)) {
info->requiredby = pm_list_add(info->requiredby, strdup(tmpp->name));
continue;
}
}
}
_alpm_log(PM_LOG_FLOW2, "updating database...");
/* Figure out whether this package was installed explicitly by the user
* or installed as a dependency for another package
*/
/* ORE
info->reason = PM_PKG_REASON_EXPLICIT;
if(pm_list_is_strin(dependonly, info->data)) {
info->reason = PM_PKG_REASON_DEPEND;
}*/
/* make an install date (in UTC) */
strncpy(info->installdate, asctime(gmtime(&t)), sizeof(info->installdate));
if(db_write(db, info, INFRQ_ALL)) {
_alpm_log(PM_LOG_ERROR, "could not update database for %s", info->name);
alpm_logaction(NULL, "error updating database for %s!", info->name);
PM_RET_ERR(PM_ERR_DB_WRITE, -1);
}
/* update dependency packages' REQUIREDBY fields */
for(lp = info->depends; lp; lp = lp->next) {
pmpkg_t *depinfo = NULL;
pmdepend_t depend;
splitdep(lp->data, &depend);
depinfo = db_scan(db, depend.name, INFRQ_DESC|INFRQ_DEPENDS);
if(depinfo == NULL) {
/* look for a provides package */
PMList *provides = _alpm_db_whatprovides(db, depend.name);
if(provides) {
/* use the first one */
depinfo = db_scan(db, ((pmpkg_t *)provides->data)->name, INFRQ_DEPENDS);
if(depinfo == NULL) {
PMList *lp;
/* wtf */
for(lp = provides; lp; lp = lp->next) {
lp->data = NULL;
}
pm_list_free(provides);
continue;
}
} else {
continue;
}
}
depinfo->requiredby = pm_list_add(depinfo->requiredby, strdup(info->name));
db_write(db, depinfo, INFRQ_DEPENDS);
FREEPKG(depinfo);
}
/* Extract the .tar.gz package */
if(tar_open(&tar, info->data, &gztype, O_RDONLY, 0, TAR_GNU) == -1) {
PM_RET_ERR(PM_ERR_PKG_OPEN, -1);
}
_alpm_log(PM_LOG_DEBUG, "extracting files...");
for(i = 0; !th_read(tar); i++) {
int nb = 0;
int notouch = 0;
char *md5_orig = NULL;
char pathname[PATH_MAX];
struct stat buf;
strncpy(pathname, th_get_pathname(tar), PATH_MAX);
if(!strcmp(pathname, ".PKGINFO") || !strcmp(pathname, ".FILELIST")) {
tar_skip_regfile(tar);
continue;
}
if(!strcmp(pathname, "._install") || !strcmp(pathname, ".INSTALL")) {
/* the install script goes inside the db */
snprintf(expath, PATH_MAX, "%s/%s-%s/install", db->path, info->name, info->version);
} else {
/* build the new pathname relative to handle->root */
snprintf(expath, PATH_MAX, "%s%s", handle->root, pathname);
}
if(!stat(expath, &buf) && !S_ISDIR(buf.st_mode)) {
/* file already exists */
if(pm_list_is_strin(pathname, handle->noupgrade)) {
notouch = 1;
} else {
if(!pmo_upgrade || oldpkg == NULL) {
nb = pm_list_is_strin(pathname, info->backup) ? 1 : 0;
} else {
/* op == PM_UPGRADE */
if((md5_orig = _alpm_needbackup(pathname, oldpkg->backup)) != 0) {
nb = 1;
}
}
}
}
if(nb) {
char *temp;
char *md5_local, *md5_pkg;
md5_local = MDFile(expath);
/* extract the package's version to a temporary file and md5 it */
temp = strdup("/tmp/pacman_XXXXXX");
mkstemp(temp);
if(tar_extract_file(tar, temp)) {
alpm_logaction("could not extract %s: %s", pathname, strerror(errno));
errors++;
continue;
}
md5_pkg = MDFile(temp);
/* append the new md5 hash to it's respective entry in info->backup
* (it will be the new orginal)
*/
for(lp = info->backup; lp; lp = lp->next) {
char *fn;
if(!lp->data) continue;
if(!strcmp((char*)lp->data, pathname)) {
/* 32 for the hash, 1 for the terminating NULL, and 1 for the tab delimiter */
MALLOC(fn, strlen(lp->data)+34);
sprintf(fn, "%s\t%s", (char*)lp->data, md5_pkg);
FREE(lp->data);
lp->data = fn;
}
}
_alpm_log(PM_LOG_FLOW2, " checking md5 hashes for %s", expath);
_alpm_log(PM_LOG_FLOW2, " current: %s", md5_local);
_alpm_log(PM_LOG_FLOW2, " new: %s", md5_pkg);
if(md5_orig) {
_alpm_log(PM_LOG_FLOW2, " original: %s", md5_orig);
}
if(!pmo_upgrade) {
/* PM_ADD */
/* if a file already exists with a different md5 hash,
* then we rename it to a .pacorig extension and continue */
if(strcmp(md5_local, md5_pkg)) {
char newpath[PATH_MAX];
snprintf(newpath, PATH_MAX, "%s.pacorig", expath);
if(rename(expath, newpath)) {
_alpm_log(PM_LOG_ERROR, "could not rename %s: %s", expath, strerror(errno));
alpm_logaction("error: could not rename %s: %s", expath, strerror(errno));
}
if(_alpm_copyfile(temp, expath)) {
_alpm_log(PM_LOG_ERROR, "could not copy %s to %s: %s", temp, expath, strerror(errno));
alpm_logaction("error: could not copy %s to %s: %s", temp, expath, strerror(errno));
errors++;
} else {
_alpm_log(PM_LOG_WARNING, "warning: %s saved as %s", expath, newpath);
alpm_logaction("warning: %s saved as %s", expath, newpath);
}
}
} else if(md5_orig) {
/* PM_UPGRADE */
int installnew = 0;
/* the fun part */
if(!strcmp(md5_orig, md5_local)) {
if(!strcmp(md5_local, md5_pkg)) {
_alpm_log(PM_LOG_FLOW2, " action: installing new file");
installnew = 1;
} else {
_alpm_log(PM_LOG_FLOW2, " action: installing new file");
installnew = 1;
}
} else if(!strcmp(md5_orig, md5_pkg)) {
_alpm_log(PM_LOG_FLOW2, " action: leaving existing file in place");
} else if(!strcmp(md5_local, md5_pkg)) {
_alpm_log(PM_LOG_FLOW2, " action: installing new file");
installnew = 1;
} else {
char newpath[PATH_MAX];
_alpm_log(PM_LOG_FLOW2, " action: saving current file and installing new one");
installnew = 1;
snprintf(newpath, PATH_MAX, "%s.pacsave", expath);
if(rename(expath, newpath)) {
_alpm_log(PM_LOG_ERROR, "could not rename %s: %s", expath, strerror(errno));
alpm_logaction("error: could not rename %s: %s", expath, strerror(errno));
} else {
_alpm_log(PM_LOG_WARNING, "warning: %s saved as %s", expath, newpath);
alpm_logaction("warning: %s saved as %s", expath, newpath);
}
}
if(installnew) {
/*_alpm_log(PM_LOG_FLOW2, " %s", expath);*/
if(_alpm_copyfile(temp, expath)) {
_alpm_log(PM_LOG_ERROR, "could not copy %s to %s: %s", temp, expath, strerror(errno));
errors++;
}
}
}
FREE(md5_local);
FREE(md5_pkg);
FREE(md5_orig);
unlink(temp);
FREE(temp);
} else {
if(!notouch) {
_alpm_log(PM_LOG_FLOW2, "%s", pathname);
} else {
_alpm_log(PM_LOG_FLOW2, "%s is in NoUpgrade - skipping", pathname);
strncat(expath, ".pacnew", PATH_MAX);
_alpm_log(PM_LOG_WARNING, "warning: extracting %s%s as %s", handle->root, pathname, expath);
alpm_logaction("warning: extracting %s%s as %s", handle->root, pathname, expath);
tar_skip_regfile(tar);
}
if(trans->flags & PM_TRANS_FLAG_FORCE) {
/* if FORCE was used, then unlink() each file (whether it's there
* or not) before extracting. this prevents the old "Text file busy"
* error that crops up if one tries to --force a glibc or pacman
* upgrade.
*/
unlink(expath);
}
if(tar_extract_file(tar, expath)) {
_alpm_log(PM_LOG_ERROR, "could not extract %s: %s", pathname, strerror(errno));
alpm_logaction("could not extract %s: %s", pathname, strerror(errno));
errors++;
}
/* calculate an md5 hash if this is in info->backup */
for(lp = info->backup; lp; lp = lp->next) {
char *fn, *md5;
char path[PATH_MAX];
if(!lp->data) continue;
if(!strcmp((char*)lp->data, pathname)) {
snprintf(path, PATH_MAX, "%s%s", handle->root, (char*)lp->data);
md5 = MDFile(path);
/* 32 for the hash, 1 for the terminating NULL, and 1 for the tab delimiter */
MALLOC(fn, strlen(lp->data)+34);
sprintf(fn, "%s\t%s", (char*)lp->data, md5);
FREE(lp->data);
lp->data = fn;
}
}
}
}
tar_close(tar);
if(errors) {
ret = 1;
_alpm_log(PM_LOG_ERROR, "errors occurred while %s %s",
(pmo_upgrade ? "upgrading" : "installing"), info->name);
alpm_logaction("errors occurred while %s %s",
(pmo_upgrade ? "upgrading" : "installing"), info->name);
}
/* run the post-install script if it exists */
snprintf(pm_install, PATH_MAX, "%s%s/%s/%s-%s/install", handle->root, handle->dbpath, db->treename, info->name, info->version);
if(pmo_upgrade) {
_alpm_runscriptlet(handle->root, pm_install, "post_upgrade", info->version, oldpkg ? oldpkg->version : NULL);
} else {
_alpm_runscriptlet(handle->root, pm_install, "post_install", info->version, NULL);
}
if(pmo_upgrade && oldpkg) {
TRANS_CB(trans, PM_TRANS_CB_UPGRADE_DONE, info, NULL);
alpm_logaction("upgraded %s (%s -> %s)", info->name,
oldpkg->version, info->version);
} else {
TRANS_CB(trans, PM_TRANS_CB_ADD_DONE, info, NULL);
alpm_logaction("installed %s (%s)", info->name, info->version);
}
FREEPKG(oldpkg);
}
/* run ldconfig if it exists */
_alpm_log(PM_LOG_FLOW2, "running \"%ssbin/ldconfig -r %s\"", handle->root, handle->root);
_alpm_ldconfig(handle->root);
return(0);
}
/* vim: set ts=2 sw=2 noet: */

34
lib/libalpm/add.h Normal file
View File

@ -0,0 +1,34 @@
/*
* add.h
*
* Copyright (c) 2002-2005 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 _ALPM_ADD_H
#define _ALPM_ADD_H
#include "list.h"
#include "db.h"
#include "trans.h"
int add_loadtarget(pmdb_t *db, pmtrans_t *trans, char *name);
int add_prepare(pmdb_t *db, pmtrans_t *trans, PMList **data);
int add_commit(pmdb_t *db, pmtrans_t *trans);
#endif /* _ALPM_ADD_H */
/* vim: set ts=2 sw=2 noet: */

577
lib/libalpm/alpm.c Normal file
View File

@ -0,0 +1,577 @@
/*
* alpm.c
*
* 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 <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <syslog.h>
#include <limits.h> /* PATH_MAX */
#include <stdarg.h>
/* pacman */
#include "log.h"
#include "error.h"
#include "rpmvercmp.h"
#include "md5.h"
#include "list.h"
#include "package.h"
#include "group.h"
#include "util.h"
#include "db.h"
#include "cache.h"
#include "deps.h"
#include "backup.h"
#include "add.h"
#include "remove.h"
#include "sync.h"
#include "handle.h"
#include "alpm.h"
pmhandle_t *handle = NULL;
enum __pmerrno_t pm_errno;
/*
* Library
*/
int alpm_initialize(char *root)
{
char str[PATH_MAX];
ASSERT(handle == NULL, PM_RET_ERR(PM_ERR_HANDLE_NOT_NULL, -1));
handle = handle_new();
/* lock db */
if(handle->access == PM_ACCESS_RW) {
if(_alpm_lckmk(PACLOCK) == -1) {
FREE(handle);
PM_RET_ERR(PM_ERR_HANDLE_LOCK, -1);
}
}
strncpy(str, (root) ? root : PACROOT, PATH_MAX);
/* add a trailing '/' if there isn't one */
if(str[strlen(str)-1] != '/') {
strcat(str, "/");
}
handle->root = strdup(str);
return(0);
}
int alpm_release()
{
PMList *i;
ASSERT(handle != NULL, PM_RET_ERR(PM_ERR_HANDLE_NULL, -1));
/* unlock db */
if(handle->access == PM_ACCESS_RW) {
if(_alpm_lckrm(PACLOCK)) {
_alpm_log(PM_LOG_WARNING, "could not remove lock file %s", PACLOCK);
alpm_logaction("warning: could not remove lock file %s", PACLOCK);
}
}
/* close local database */
if(handle->db_local) {
db_close(handle->db_local);
handle->db_local = NULL;
}
/* and also sync ones */
for(i = handle->dbs_sync; i; i = i->next) {
if(i->data) {
db_close(i->data);
i->data = NULL;
}
}
FREEHANDLE(handle);
return(0);
}
/*
* Options
*/
int alpm_set_option(unsigned char parm, unsigned long data)
{
/* Sanity checks */
ASSERT(handle != NULL, PM_RET_ERR(PM_ERR_HANDLE_NULL, -1));
return(handle_set_option(handle, parm, data));
}
int alpm_get_option(unsigned char parm, long *data)
{
/* Sanity checks */
ASSERT(handle != NULL, PM_RET_ERR(PM_ERR_HANDLE_NULL, -1));
return(handle_get_option(handle, parm, data));
}
/*
* Databases
*/
int alpm_db_register(char *treename, PM_DB **db)
{
/* Sanity checks */
ASSERT(handle != NULL, PM_RET_ERR(PM_ERR_HANDLE_NULL, -1));
ASSERT(treename != NULL && strlen(treename) != 0, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
ASSERT(db != NULL, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
/* check if the db if already registered */
*db = db_open(handle->root, handle->dbpath, treename);
if(*db == NULL) {
/* couldn't open the db directory - try creating it */
if(db_create(handle->root, handle->dbpath, treename) == -1) {
PM_RET_ERR(PM_ERR_DB_CREATE, -1);
}
*db = db_open(handle->root, handle->dbpath, treename);
if(*db == NULL) {
/* couldn't open the db directory, try creating it */
PM_RET_ERR(PM_ERR_DB_OPEN, -1);
}
}
if(strcmp(treename, "local") == 0) {
handle->db_local = *db;
} else {
handle->dbs_sync = pm_list_add(handle->dbs_sync, *db);
}
return(0);
}
int alpm_db_unregister(PM_DB *db)
{
PMList *i;
int found = 0;
/* Sanity checks */
ASSERT(handle != NULL, PM_RET_ERR(PM_ERR_HANDLE_NULL, -1));
ASSERT(db != NULL, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
if(db == handle->db_local) {
db_close(handle->db_local);
handle->db_local = NULL;
found = 1;
} else {
for(i = handle->dbs_sync; i && !found; i = i->next) {
if(db == i->data) {
db_close(i->data);
i->data = NULL;
/* ORE
it should be _alpm_list_removed instead */
found = 1;
}
}
}
if(!found) {
PM_RET_ERR(PM_ERR_DB_NOT_FOUND, -1);
}
return(0);
}
PM_PKG *alpm_db_readpkg(PM_DB *db, char *name)
{
/* Sanity checks */
ASSERT(handle != NULL, return(NULL));
ASSERT(db != NULL, return(NULL));
ASSERT(name != NULL && strlen(name) != 0, return(NULL));
return(db_get_pkgfromcache(db, name));
}
PM_LIST *alpm_db_getpkgcache(PM_DB *db)
{
/* Sanity checks */
ASSERT(handle != NULL, return(NULL));
ASSERT(db != NULL, return(NULL));
return(db_get_pkgcache(db));
}
PM_GRP *alpm_db_readgrp(PM_DB *db, char *name)
{
/* Sanity checks */
ASSERT(handle != NULL, return(NULL));
ASSERT(db != NULL, return(NULL));
ASSERT(name != NULL && strlen(name) != 0, return(NULL));
return(db_get_grpfromcache(db, name));
}
PM_LIST *alpm_db_getgrpcache(PM_DB *db)
{
/* Sanity checks */
ASSERT(handle != NULL, return(NULL));
ASSERT(db != NULL, return(NULL));
return(db_get_grpcache(db));
}
PM_LIST *alpm_db_nextgrp(PM_LIST *cache)
{
/* Sanity checks */
ASSERT(handle != NULL, return(NULL));
ASSERT(cache != NULL, return(NULL));
return(cache->next);
}
PM_GRP *alpm_db_getgrp(PM_LIST *cache)
{
/* Sanity checks */
ASSERT(handle != NULL, return(NULL));
ASSERT(cache != NULL, return(NULL));
return(cache->data);
}
/*
* Packages
*/
void *alpm_pkg_getinfo(PM_PKG *pkg, unsigned char parm)
{
void *data;
/* Sanity checks */
ASSERT(handle != NULL, return(NULL));
ASSERT(pkg != NULL, return(NULL));
/* Update the cache package entry if needed */
if(pkg->origin == PKG_FROM_CACHE && pkg->data == handle->db_local) {
switch(parm) {
case PM_PKG_FILES:
case PM_PKG_BACKUP:
if(!(pkg->infolevel & INFRQ_FILES)) {
char target[321]; /* 256+1+64 */
snprintf(target, 321, "%s-%s", pkg->name, pkg->version);
db_read(pkg->data, target, INFRQ_FILES, pkg);
}
break;
case PM_PKG_SCRIPLET:
if(!(pkg->infolevel & INFRQ_SCRIPLET)) {
char target[321];
snprintf(target, 321, "%s-%s", pkg->name, pkg->version);
db_read(pkg->data, target, INFRQ_SCRIPLET, pkg);
}
break;
}
}
switch(parm) {
case PM_PKG_NAME: data = pkg->name; break;
case PM_PKG_VERSION: data = pkg->version; break;
case PM_PKG_DESC: data = pkg->desc; break;
case PM_PKG_GROUPS: data = pkg->groups; break;
case PM_PKG_URL: data = pkg->url; break;
case PM_PKG_LICENSE: data = pkg->license; break;
case PM_PKG_ARCH: data = pkg->arch; break;
case PM_PKG_BUILDDATE: data = pkg->builddate; break;
case PM_PKG_INSTALLDATE: data = pkg->installdate; break;
case PM_PKG_PACKAGER: data = pkg->packager; break;
case PM_PKG_SIZE: data = (void *)pkg->size; break;
case PM_PKG_REASON: data = (void *)(int)pkg->reason; break;
case PM_PKG_REPLACES: data = pkg->replaces; break;
case PM_PKG_MD5SUM: data = pkg->md5sum; break;
case PM_PKG_DEPENDS: data = pkg->depends; break;
case PM_PKG_REQUIREDBY: data = pkg->requiredby; break;
case PM_PKG_PROVIDES: data = pkg->provides; break;
case PM_PKG_CONFLICTS: data = pkg->conflicts; break;
case PM_PKG_FILES: data = pkg->files; break;
case PM_PKG_BACKUP: data = pkg->backup; break;
case PM_PKG_SCRIPLET: data = (void *)(int)pkg->scriptlet; break;
default:
data = NULL;
break;
}
return(data);
}
int alpm_pkg_load(char *filename, PM_PKG **pkg)
{
/* Sanity checks */
ASSERT(filename != NULL && strlen(filename) != 0, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
ASSERT(pkg != NULL, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
*pkg = pkg_load(filename);
if(*pkg == NULL) {
/* pm_errno is set by pkg_load */
return(-1);
}
return(0);
}
int alpm_pkg_free(PM_PKG *pkg)
{
/* Sanity checks */
ASSERT(pkg != NULL, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
pkg_free(pkg);
return(0);
}
int alpm_pkg_vercmp(const char *ver1, const char *ver2)
{
return(rpmvercmp(ver1, ver2));
}
/*
* Groups
*/
void *alpm_grp_getinfo(PM_GRP *grp, unsigned char parm)
{
void *data;
/* Sanity checks */
ASSERT(grp != NULL, return(NULL));
switch(parm) {
case PM_GRP_NAME: data = grp->name; break;
case PM_GRP_PKGNAMES: data = grp->packages; break;
default:
data = NULL;
break;
}
return(data);
}
/*
* Sync operations
*/
void *alpm_sync_getinfo(PM_SYNC *sync, unsigned char parm)
{
void *data;
/* Sanity checks */
ASSERT(sync != NULL, return(NULL));
switch(parm) {
case PM_SYNC_TYPE: data = (void *)(int)sync->type; break;
case PM_SYNC_LOCALPKG: data = sync->lpkg; break;
case PM_SYNC_SYNCPKG: data = sync->spkg; break;
default:
data = NULL;
break;
}
return(data);
}
int alpm_sync_sysupgrade(PM_LIST **data)
{
ASSERT(handle != NULL, PM_RET_ERR(PM_ERR_HANDLE_NULL, -1));
ASSERT(data != NULL, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
return(sync_sysupgrade(data));
}
/*
* Transactions
*/
void *alpm_trans_getinfo(unsigned char parm)
{
pmtrans_t *trans;
void *data;
/* Sanity checks */
ASSERT(handle != NULL, return(NULL));
trans = handle->trans;
switch(parm) {
case PM_TRANS_TYPE: data = (void *)(int)trans->type; break;
case PM_TRANS_FLAGS: data = (void *)(int)trans->flags; break;
case PM_TRANS_TARGETS: data = trans->targets; break;
default:
data = NULL;
break;
}
return(data);
}
int alpm_trans_init(unsigned char type, unsigned char flags, alpm_trans_cb cb)
{
/* Sanity checks */
ASSERT(handle != NULL, PM_RET_ERR(PM_ERR_HANDLE_NULL, -1));
ASSERT(handle->trans == NULL, PM_RET_ERR(PM_ERR_TRANS_NOT_NULL, -1));
handle->trans = trans_new();
if(handle->trans == NULL) {
PM_RET_ERR(PM_ERR_MEMORY, -1);
}
return(trans_init(handle->trans, type, flags, cb));
}
int alpm_trans_addtarget(char *target)
{
pmtrans_t *trans;
/* Sanity checks */
ASSERT(handle != NULL, PM_RET_ERR(PM_ERR_HANDLE_NULL, -1));
ASSERT(target != NULL && strlen(target) != 0, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
trans = handle->trans;
ASSERT(trans != NULL, PM_RET_ERR(PM_ERR_TRANS_NULL, -1));
ASSERT(trans->state == STATE_INITIALIZED, PM_RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1));
return(trans_addtarget(trans, target));
}
int alpm_trans_prepare(PMList **data)
{
pmtrans_t *trans;
/* Sanity checks */
ASSERT(handle != NULL, PM_RET_ERR(PM_ERR_HANDLE_NULL, -1));
ASSERT(data != NULL, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
trans = handle->trans;
ASSERT(trans != NULL, PM_RET_ERR(PM_ERR_TRANS_NULL, -1));
ASSERT(trans->state == STATE_INITIALIZED, PM_RET_ERR(PM_ERR_TRANS_NOT_INITIALIZED, -1));
return(trans_prepare(handle->trans, data));
}
int alpm_trans_commit()
{
pmtrans_t *trans;
/* Sanity checks */
ASSERT(handle != NULL, PM_RET_ERR(PM_ERR_HANDLE_NULL, -1));
trans = handle->trans;
ASSERT(trans != NULL, PM_RET_ERR(PM_ERR_TRANS_NULL, -1));
ASSERT(trans->state == STATE_PREPARED, PM_RET_ERR(PM_ERR_TRANS_NOT_PREPARED, -1));
/* ORE
ASSERT(handle->access != PM_ACCESS_RW, PM_RET_ERR(PM_ERR_BAD_PERMS, -1));*/
return(trans_commit(handle->trans));
}
int alpm_trans_release()
{
pmtrans_t *trans;
/* Sanity checks */
ASSERT(handle != NULL, PM_RET_ERR(PM_ERR_HANDLE_NULL, -1));
trans = handle->trans;
ASSERT(trans != NULL, PM_RET_ERR(PM_ERR_TRANS_NULL, -1));
ASSERT(trans->state != STATE_IDLE, PM_RET_ERR(PM_ERR_TRANS_NULL, -1));
FREETRANS(handle->trans);
return(0);
}
/*
* Log facilities
*/
int alpm_logaction(char *fmt, ...)
{
char str[256];
va_list args;
va_start(args, fmt);
vsnprintf(str, 256, fmt, args);
va_end(args);
return(_alpm_log_action(handle->usesyslog, handle->logfd, str));
}
/*
* Lists wrappers
*/
PM_LIST *alpm_list_first(PM_LIST *list)
{
ASSERT(list != NULL, return(NULL));
return(list);
}
PM_LIST *alpm_list_next(PM_LIST *entry)
{
ASSERT(entry != NULL, return(NULL));
return(entry->next);
}
void *alpm_list_getdata(PM_LIST *entry)
{
ASSERT(entry != NULL, return(NULL));
return(entry->data);
}
int alpm_list_free(PM_LIST *entry)
{
if(entry) {
/* ORE
does not free all memory for packages... */
pm_list_free(entry);
}
return(0);
}
/*
* Misc wrappers
*/
char *alpm_get_md5sum(char *name)
{
ASSERT(name != NULL, return(NULL));
return(MDFile(name));
}
/* vim: set ts=2 sw=2 noet: */

330
lib/libalpm/alpm.h Normal file
View File

@ -0,0 +1,330 @@
/*
* alpm.h
*
* Copyright (c) 2002-2005 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 _ALPM_H
#define _ALPM_H
/*
* Arch Linux Package Management library
*/
/*
* Structures (opaque)
*/
typedef struct __pmlist_t PM_LIST;
typedef struct __pmdb_t PM_DB;
typedef struct __pmpkg_t PM_PKG;
typedef struct __pmgrp_t PM_GRP;
typedef struct __pmsync_t PM_SYNC;
typedef struct __pmtrans_t PM_TRANS;
/* ORE
typedef struct __pmdepend_t PM_DEP;
typedef struct __pmdepmissing_t PM_DEPMISS; */
/*
* Library
*/
/* Version */
#define ALPM_VERSION "0.1.0"
int alpm_initialize(char *root);
int alpm_release();
/*
* Logging facilities
*/
/* Levels */
#define PM_LOG_DEBUG 0x01
#define PM_LOG_ERROR 0x02
#define PM_LOG_WARNING 0x04
#define PM_LOG_FLOW1 0x08
#define PM_LOG_FLOW2 0x10
#define PM_LOG_FUNCTION 0x20
int alpm_logaction(char *fmt, ...);
/*
* Options
*/
/* Parameters */
enum {
PM_OPT_LOGCB = 1,
PM_OPT_LOGMASK,
PM_OPT_USESYSLOG,
PM_OPT_ROOT,
PM_OPT_DBPATH,
PM_OPT_LOGFILE,
PM_OPT_LOCALDB,
PM_OPT_SYNCDB,
PM_OPT_NOUPGRADE,
PM_OPT_IGNOREPKG,
PM_OPT_HOLDPKG
};
int alpm_set_option(unsigned char parm, unsigned long data);
int alpm_get_option(unsigned char parm, long *data);
/*
* Databases
*/
int alpm_db_register(char *treename, PM_DB **db);
int alpm_db_unregister(PM_DB *db);
PM_PKG *alpm_db_readpkg(PM_DB *db, char *name);
PM_LIST *alpm_db_getpkgcache(PM_DB *db);
PM_GRP *alpm_db_readgrp(PM_DB *db, char *name);
PM_LIST *alpm_db_getgrpcache(PM_DB *db);
/*
* Packages
*/
/* Info parameters */
enum {
/* Desc entry */
PM_PKG_NAME = 1,
PM_PKG_VERSION,
PM_PKG_DESC,
PM_PKG_GROUPS,
PM_PKG_URL,
PM_PKG_LICENSE,
PM_PKG_ARCH,
PM_PKG_BUILDDATE,
PM_PKG_INSTALLDATE,
PM_PKG_PACKAGER,
PM_PKG_SIZE,
PM_PKG_REASON,
PM_PKG_REPLACES, /* Sync DB only */
PM_PKG_MD5SUM, /* Sync DB only */
/* Depends entry */
PM_PKG_DEPENDS,
PM_PKG_REQUIREDBY,
PM_PKG_CONFLICTS,
PM_PKG_PROVIDES,
/* Files entry */
PM_PKG_FILES,
PM_PKG_BACKUP,
/* Sciplet */
PM_PKG_SCRIPLET
};
/* reasons -- ie, why the package was installed */
#define PM_PKG_REASON_EXPLICIT 0 /* explicitly requested by the user */
#define PM_PKG_REASON_DEPEND 1 /* installed as a dependency for another package */
void *alpm_pkg_getinfo(PM_PKG *pkg, unsigned char parm);
int alpm_pkg_load(char *filename, PM_PKG **pkg);
int alpm_pkg_free(PM_PKG *pkg);
int alpm_pkg_vercmp(const char *ver1, const char *ver2);
/*
* Groups
*/
/* Info parameters */
enum {
PM_GRP_NAME = 1,
PM_GRP_PKGNAMES
};
void *alpm_grp_getinfo(PM_GRP *grp, unsigned char parm);
/*
* Sync
*/
/* Types */
enum {
PM_SYSUPG_REPLACE = 1,
PM_SYSUPG_UPGRADE,
PM_SYSUPG_DEPEND
};
/* Info parameters */
enum {
PM_SYNC_TYPE = 1,
PM_SYNC_LOCALPKG,
PM_SYNC_SYNCPKG
};
void *alpm_sync_getinfo(PM_SYNC *sync, unsigned char parm);
int alpm_sync_sysupgrade(PM_LIST **data);
/*
* Transactions
*/
/* Types */
enum {
PM_TRANS_TYPE_ADD = 1,
PM_TRANS_TYPE_REMOVE,
PM_TRANS_TYPE_UPGRADE,
PM_TRANS_TYPE_SYNC
};
/* Flags */
#define PM_TRANS_FLAG_NODEPS 0x01
#define PM_TRANS_FLAG_FORCE 0x02
#define PM_TRANS_FLAG_NOSAVE 0x04
#define PM_TRANS_FLAG_FRESHEN 0x08
#define PM_TRANS_FLAG_CASCADE 0x10
#define PM_TRANS_FLAG_RECURSE 0x20
#define PM_TRANS_FLAG_DBONLY 0x40
/* Callback events */
enum {
PM_TRANS_CB_DEPS_START = 1,
PM_TRANS_CB_DEPS_DONE,
PM_TRANS_CB_CONFLICTS_START,
PM_TRANS_CB_CONFLICTS_DONE,
PM_TRANS_CB_ADD_START,
PM_TRANS_CB_ADD_DONE,
PM_TRANS_CB_REMOVE_START,
PM_TRANS_CB_REMOVE_DONE,
PM_TRANS_CB_UPGRADE_START,
PM_TRANS_CB_UPGRADE_DONE
};
/* Callback */
typedef void (*alpm_trans_cb)(unsigned short, void *, void *);
/* Info parameters */
enum {
PM_TRANS_TYPE = 1,
PM_TRANS_FLAGS,
PM_TRANS_TARGETS
};
/* Dependencies */
enum {
PM_DEP_ANY = 1,
PM_DEP_EQ,
PM_DEP_GE,
PM_DEP_LE
};
enum {
PM_DEP_DEPEND = 1,
PM_DEP_REQUIRED,
PM_DEP_CONFLICT
};
/* ORE
to be deprecated in favor of PM_DEP and PM_DEPMISS (opaque) */
typedef struct __pmdepend_t {
unsigned short mod;
char name[256];
char version[64];
} pmdepend_t;
typedef struct __pmdepmissing_t {
unsigned char type;
char target[256];
pmdepend_t depend;
} pmdepmissing_t;
void *alpm_trans_getinfo(unsigned char parm);
int alpm_trans_init(unsigned char type, unsigned char flags, alpm_trans_cb cb);
int alpm_trans_addtarget(char *target);
int alpm_trans_prepare(PM_LIST **data);
int alpm_trans_commit();
int alpm_trans_release();
/*
* PM_LIST helpers
*/
PM_LIST *alpm_list_first(PM_LIST *list);
PM_LIST *alpm_list_next(PM_LIST *entry);
void *alpm_list_getdata(PM_LIST *entry);
int alpm_list_free(PM_LIST *entry);
/*
* Helpers
*/
char *alpm_get_md5sum(char *name);
/*
* Errors
*/
extern enum __pmerrno_t {
PM_ERR_NOERROR = 1,
PM_ERR_MEMORY,
PM_ERR_SYSTEM,
PM_ERR_BADPERMS,
PM_ERR_NOT_A_FILE,
PM_ERR_WRONG_ARGS,
/* Interface */
PM_ERR_HANDLE_NULL,
PM_ERR_HANDLE_NOT_NULL,
PM_ERR_HANDLE_LOCK,
/* Databases */
PM_ERR_DB_OPEN,
PM_ERR_DB_CREATE,
PM_ERR_DB_NULL,
PM_ERR_DB_NOT_FOUND,
PM_ERR_DB_NOT_NULL,
PM_ERR_DB_WRITE,
/* Cache */
PM_ERR_CACHE_NULL,
/* Configuration */
PM_ERR_OPT_LOGFILE,
PM_ERR_OPT_DBPATH,
PM_ERR_OPT_LOCALDB,
PM_ERR_OPT_SYNCDB,
PM_ERR_OPT_USESYSLOG,
/* Transactions */
PM_ERR_TRANS_NOT_NULL,
PM_ERR_TRANS_NULL,
PM_ERR_TRANS_DUP_TARGET,
PM_ERR_TRANS_INITIALIZED,
PM_ERR_TRANS_NOT_INITIALIZED,
PM_ERR_TRANS_NOT_PREPARED,
PM_ERR_TRANS_ABORT,
/* Packages */
PM_ERR_PKG_NOT_FOUND,
PM_ERR_PKG_INVALID,
PM_ERR_PKG_OPEN,
PM_ERR_PKG_LOAD,
PM_ERR_PKG_INSTALLED,
PM_ERR_PKG_CANT_FRESH,
PM_ERR_INVALID_NAME,
/* Groups */
PM_ERR_GRP_NOT_FOUND,
/* Dependencies */
PM_ERR_UNSATISFIED_DEPS,
PM_ERR_CONFLICTING_DEPS,
PM_ERR_UNRESOLVABLE_DEPS,
PM_ERR_FILE_CONFLICTS,
/* Misc */
PM_ERR_USER_ABORT,
PM_ERR_INTERNAL_ERROR
} pm_errno;
char *alpm_strerror(int err);
#endif /* _ALPM_H */
/* vim: set ts=2 sw=2 noet: */

63
lib/libalpm/backup.c Normal file
View File

@ -0,0 +1,63 @@
/*
* backup.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdlib.h>
#include <string.h>
/* pacman */
#include "backup.h"
/* Look for a filename in a pkginfo_t.backup list. If we find it,
* then we return the md5 hash (parsed from the same line)
*/
char *_alpm_needbackup(char* file, PMList *backup)
{
PMList *lp;
if(file == NULL || backup == NULL) {
return(NULL);
}
/* run through the backup list and parse out the md5 hash for our file */
for(lp = backup; lp; lp = lp->next) {
char *str = strdup(lp->data);
char *ptr;
/* tab delimiter */
ptr = strchr(str, '\t');
if(ptr == NULL) {
free(str);
continue;
}
*ptr = '\0';
ptr++;
/* now str points to the filename and ptr points to the md5 hash */
if(!strcmp(file, str)) {
free(str);
return(strdup(ptr));
}
free(str);
}
return(NULL);
}
/* vim: set ts=2 sw=2 noet: */

30
lib/libalpm/backup.h Normal file
View File

@ -0,0 +1,30 @@
/*
* backup.h
*
* Copyright (c) 2002-2005 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 _ALPM_BACKUP_H
#define _ALPM_BACKUP_H
#include "list.h"
char *_alpm_needbackup(char* file, PMList *backup);
#endif /* _ALPM_BACKUP_H */
/* vim: set ts=2 sw=2 noet: */

203
lib/libalpm/cache.c Normal file
View File

@ -0,0 +1,203 @@
/*
* cache.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
/* pacman */
#include "list.h"
#include "package.h"
#include "group.h"
#include "db.h"
#include "cache.h"
/* Returns a new package cache from db.
* It frees the cache if it already exists.
*/
int db_load_pkgcache(pmdb_t *db)
{
pmpkg_t *info;
if(db == NULL) {
return(-1);
}
db_free_pkgcache(db);
db_rewind(db);
while((info = db_scan(db, NULL, INFRQ_DESC|INFRQ_DEPENDS)) != NULL) {
info->origin = PKG_FROM_CACHE;
info->data = db;
/* add to the collective */
db->pkgcache = pm_list_add_sorted(db->pkgcache, info, pkg_cmp);
}
return(0);
}
void db_free_pkgcache(pmdb_t *db)
{
if(db == NULL || db->pkgcache == NULL) {
return;
}
FREELISTPKGS(db->pkgcache);
if(db->grpcache) {
db_free_grpcache(db);
}
}
PMList *db_get_pkgcache(pmdb_t *db)
{
if(db == NULL) {
return(NULL);
}
if(db->pkgcache == NULL) {
db_load_pkgcache(db);
}
return(db->pkgcache);
}
pmpkg_t *db_get_pkgfromcache(pmdb_t *db, char *target)
{
PMList *i;
if(db == NULL || target == NULL || strlen(target) == 0) {
return(NULL);
}
for(i = db_get_pkgcache(db); i; i = i->next) {
pmpkg_t *info = i->data;
if(strcmp(info->name, target) == 0) {
return(info);
}
}
return(NULL);
}
/* Returns a new group cache from db.
* It frees the cache if it already exists.
*/
int db_load_grpcache(pmdb_t *db)
{
PMList *lp;
if(db == NULL) {
return(-1);
}
if(db->pkgcache == NULL) {
db_load_pkgcache(db);
}
for(lp = db->pkgcache; lp; lp = lp->next) {
PMList *i;
pmpkg_t *pkg = lp->data;
for(i = pkg->groups; i; i = i->next) {
if(!pm_list_is_strin(i->data, db->grpcache)) {
pmgrp_t *grp = grp_new();
strncpy(grp->name, (char *)i->data, 256);
grp->packages = pm_list_add_sorted(grp->packages, pkg->name, grp_cmp);
db->grpcache = pm_list_add_sorted(db->grpcache, grp, grp_cmp);
} else {
PMList *j;
for(j = db->grpcache; j; j = j->next) {
pmgrp_t *grp = j->data;
if(strcmp(grp->name, i->data) == 0) {
if(!pm_list_is_strin(pkg->name, grp->packages)) {
grp->packages = pm_list_add_sorted(grp->packages, (char *)pkg->name, grp_cmp);
}
}
}
}
}
}
return(0);
}
void db_free_grpcache(pmdb_t *db)
{
PMList *lg;
if(db == NULL || db->grpcache == NULL) {
return;
}
for(lg = db->grpcache; lg; lg = lg->next) {
PMList *lp;
pmgrp_t *grp = lg->data;
for(lp = grp->packages; lp; lp = lp->next) {
lp->data = NULL;
}
FREELIST(grp->packages);
FREEGRP(lg->data);
}
FREELIST(db->grpcache);
}
PMList *db_get_grpcache(pmdb_t *db)
{
if(db == NULL) {
return(NULL);
}
if(db->grpcache == NULL) {
db_load_grpcache(db);
}
return(db->grpcache);
}
pmgrp_t *db_get_grpfromcache(pmdb_t *db, char *target)
{
PMList *i;
if(db == NULL || target == NULL || strlen(target) == 0) {
return(NULL);
}
for(i = db_get_grpcache(db); i; i = i->next) {
pmgrp_t *info = i->data;
if(strcmp(info->name, target) == 0) {
return(info);
}
}
return(NULL);
}
/* vim: set ts=2 sw=2 noet: */

42
lib/libalpm/cache.h Normal file
View File

@ -0,0 +1,42 @@
/*
* cache.h
*
* Copyright (c) 2002-2005 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 _ALPM_CACHE_H
#define _ALPM_CACHE_H
#include "list.h"
#include "package.h"
#include "group.h"
#include "db.h"
/* packages */
int db_load_pkgcache(pmdb_t *db);
void db_free_pkgcache(pmdb_t *db);
PMList *db_get_pkgcache(pmdb_t *db);
pmpkg_t *db_get_pkgfromcache(pmdb_t *db, char *target);
/* groups */
int db_load_grpcache(pmdb_t *db);
void db_free_grpcache(pmdb_t *db);
PMList *db_get_grpcache(pmdb_t *db);
pmgrp_t *db_get_grpfromcache(pmdb_t *db, char *target);
#endif /* _ALPM_CACHE_H */
/* vim: set ts=2 sw=2 noet: */

651
lib/libalpm/db.c Normal file
View File

@ -0,0 +1,651 @@
/*
* db.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
/* pacman */
#include "util.h"
#include "group.h"
#include "cache.h"
#include "db.h"
/* Open a database and return a pmdb_t handle */
pmdb_t *db_open(char *root, char *dbpath, char *treename)
{
pmdb_t *db;
if(root == NULL || dbpath == NULL || treename == NULL) {
return(NULL);
}
MALLOC(db, sizeof(pmdb_t));
MALLOC(db->path, strlen(root)+strlen(dbpath)+strlen(treename)+2);
sprintf(db->path, "%s%s/%s", root, dbpath, treename);
db->dir = opendir(db->path);
if(db->dir == NULL) {
FREE(db->path);
FREE(db);
return(NULL);
}
strncpy(db->treename, treename, sizeof(db->treename)-1);
db->pkgcache = NULL;
db->grpcache = NULL;
return(db);
}
void db_close(pmdb_t *db)
{
if(db == NULL) {
return;
}
if(db->dir) {
closedir(db->dir);
db->dir = NULL;
}
FREE(db->path);
db_free_pkgcache(db);
db_free_grpcache(db);
free(db);
return;
}
int db_create(char *root, char *dbpath, char *treename)
{
char path[PATH_MAX];
if(root == NULL || dbpath == NULL || treename == NULL) {
return(-1);
}
snprintf(path, PATH_MAX, "%s%s/local", root, dbpath);
if(_alpm_makepath(path) != 0) {
return(-1);
}
return(0);
}
void db_rewind(pmdb_t *db)
{
if(db == NULL || db->dir == NULL) {
return;
}
rewinddir(db->dir);
}
pmpkg_t *db_scan(pmdb_t *db, char *target, unsigned int inforeq)
{
struct dirent *ent = NULL;
char name[256];
char *ptr = NULL;
int ret, found = 0;
pmpkg_t *pkg;
if(db == NULL) {
return(NULL);
}
if(target != NULL) {
/* search for a specific package (by name only) */
rewinddir(db->dir);
while(!found && (ent = readdir(db->dir)) != NULL) {
if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
continue;
}
strncpy(name, ent->d_name, 255);
/* truncate the string at the second-to-last hyphen, */
/* which will give us the package name */
if((ptr = rindex(name, '-'))) {
*ptr = '\0';
}
if((ptr = rindex(name, '-'))) {
*ptr = '\0';
}
if(!strcmp(name, target)) {
found = 1;
}
}
if(!found) {
return(NULL);
}
} else {
/* normal iteration */
ent = readdir(db->dir);
if(ent == NULL) {
return(NULL);
}
if(!strcmp(ent->d_name, ".")) {
ent = readdir(db->dir);
if(ent == NULL) {
return(NULL);
}
}
if(!strcmp(ent->d_name, "..")) {
ent = readdir(db->dir);
if(ent == NULL) {
return(NULL);
}
}
}
pkg = pkg_new();
if(pkg == NULL) {
return(NULL);
}
ret = db_read(db, ent->d_name, inforeq, pkg);
if(ret == -1) {
FREEPKG(pkg);
}
return(ret == 0 ? pkg : NULL);
}
int db_read(pmdb_t *db, char *name, unsigned int inforeq, pmpkg_t *info)
{
FILE *fp = NULL;
struct stat buf;
char path[PATH_MAX];
char line[512];
if(db == NULL || name == NULL || info == NULL) {
return(-1);
}
snprintf(path, PATH_MAX, "%s/%s", db->path, name);
if(stat(path, &buf)) {
/* directory doesn't exist or can't be opened */
return(-1);
}
/* DESC */
if(inforeq & INFRQ_DESC) {
snprintf(path, PATH_MAX, "%s/%s/desc", db->path, name);
fp = fopen(path, "r");
if(fp == NULL) {
fprintf(stderr, "error: %s: %s\n", path, strerror(errno));
return(-1);
}
while(!feof(fp)) {
if(fgets(line, 256, fp) == NULL) {
break;
}
_alpm_strtrim(line);
if(!strcmp(line, "%NAME%")) {
if(fgets(info->name, sizeof(info->name), fp) == NULL) {
return(-1);
}
_alpm_strtrim(info->name);
} else if(!strcmp(line, "%VERSION%")) {
if(fgets(info->version, sizeof(info->version), fp) == NULL) {
return(-1);
}
_alpm_strtrim(info->version);
} else if(!strcmp(line, "%DESC%")) {
if(fgets(info->desc, sizeof(info->desc), fp) == NULL) {
return(-1);
}
_alpm_strtrim(info->desc);
} else if(!strcmp(line, "%GROUPS%")) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
char *s = strdup(line);
info->groups = pm_list_add(info->groups, s);
}
} else if(!strcmp(line, "%URL%")) {
if(fgets(info->url, sizeof(info->url), fp) == NULL) {
return(-1);
}
_alpm_strtrim(info->url);
} else if(!strcmp(line, "%LICENSE%")) {
if(fgets(info->license, sizeof(info->license), fp) == NULL) {
return(-1);
}
_alpm_strtrim(info->license);
} else if(!strcmp(line, "%ARCH%")) {
if(fgets(info->arch, sizeof(info->arch), fp) == NULL) {
return(-1);
}
_alpm_strtrim(info->arch);
} else if(!strcmp(line, "%BUILDDATE%")) {
if(fgets(info->builddate, sizeof(info->builddate), fp) == NULL) {
return(-1);
}
_alpm_strtrim(info->builddate);
} else if(!strcmp(line, "%INSTALLDATE%")) {
if(fgets(info->installdate, sizeof(info->installdate), fp) == NULL) {
return(-1);
}
_alpm_strtrim(info->installdate);
} else if(!strcmp(line, "%PACKAGER%")) {
if(fgets(info->packager, sizeof(info->packager), fp) == NULL) {
return(-1);
}
_alpm_strtrim(info->packager);
} else if(!strcmp(line, "%REASON%")) {
char tmp[32];
if(fgets(tmp, sizeof(tmp), fp) == NULL) {
return(-1);
}
_alpm_strtrim(tmp);
info->reason = atol(tmp);
} else if(!strcmp(line, "%SIZE%")) {
char tmp[32];
if(fgets(tmp, sizeof(tmp), fp) == NULL) {
return(-1);
}
_alpm_strtrim(tmp);
info->size = atol(tmp);
} else if(!strcmp(line, "%CSIZE%")) {
/* NOTE: the CSIZE and SIZE fields both share the "size" field
* in the pkginfo_t struct. This can be done b/c CSIZE
* is currently only used in sync databases, and SIZE is
* only used in local databases.
*/
char tmp[32];
if(fgets(tmp, sizeof(tmp), fp) == NULL) {
return(-1);
}
_alpm_strtrim(tmp);
info->size = atol(tmp);
} else if(!strcmp(line, "%REPLACES%")) {
/* the REPLACES tag is special -- it only appears in sync repositories,
* not the local one. */
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
info->replaces = pm_list_add(info->replaces, strdup(line));
}
} else if(!strcmp(line, "%MD5SUM%")) {
/* MD5SUM tag only appears in sync repositories,
* not the local one. */
if(fgets(info->md5sum, sizeof(info->md5sum), fp) == NULL) {
return(-1);
}
} else if(!strcmp(line, "%FORCE%")) {
/* FORCE tag only appears in sync repositories,
* not the local one. */
info->force = 1;
}
}
fclose(fp);
}
/* FILES */
if(inforeq & INFRQ_FILES) {
snprintf(path, PATH_MAX, "%s/%s/files", db->path, name);
fp = fopen(path, "r");
if(fp == NULL) {
fprintf(stderr, "error: %s: %s\n", path, strerror(errno));
return(-1);
}
while(fgets(line, 256, fp)) {
_alpm_strtrim(line);
if(!strcmp(line, "%FILES%")) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
info->files = pm_list_add(info->files, strdup(line));
}
} else if(!strcmp(line, "%BACKUP%")) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
info->backup = pm_list_add(info->backup, strdup(line));
}
}
}
fclose(fp);
}
/* DEPENDS */
if(inforeq & INFRQ_DEPENDS) {
snprintf(path, PATH_MAX, "%s/%s/depends", db->path, name);
fp = fopen(path, "r");
if(fp == NULL) {
fprintf(stderr, "error: %s: %s\n", path, strerror(errno));
return(-1);
}
while(!feof(fp)) {
fgets(line, 255, fp);
_alpm_strtrim(line);
if(!strcmp(line, "%DEPENDS%")) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
info->depends = pm_list_add(info->depends, strdup(line));
}
} else if(!strcmp(line, "%REQUIREDBY%")) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
info->requiredby = pm_list_add(info->requiredby, strdup(line));
}
} else if(!strcmp(line, "%CONFLICTS%")) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
info->conflicts = pm_list_add(info->conflicts, strdup(line));
}
} else if(!strcmp(line, "%PROVIDES%")) {
while(fgets(line, 512, fp) && strlen(_alpm_strtrim(line))) {
info->provides = pm_list_add(info->provides, strdup(line));
}
}
}
fclose(fp);
}
/* INSTALL */
if(inforeq & INFRQ_SCRIPLET) {
snprintf(path, PATH_MAX, "%s/%s/install", db->path, name);
if(!stat(path, &buf)) {
info->scriptlet = 1;
}
}
/* internal */
info->infolevel |= inforeq;
return(0);
}
int db_write(pmdb_t *db, pmpkg_t *info, unsigned int inforeq)
{
char topdir[PATH_MAX];
FILE *fp = NULL;
char path[PATH_MAX];
mode_t oldmask;
PMList *lp = NULL;
if(db == NULL || info == NULL) {
return(-1);
}
snprintf(topdir, PATH_MAX, "%s/%s-%s", db->path,
info->name, info->version);
oldmask = umask(0000);
mkdir(topdir, 0755);
/* make sure we have a sane umask */
umask(0022);
/* DESC */
if(inforeq & INFRQ_DESC) {
snprintf(path, PATH_MAX, "%s/desc", topdir);
if((fp = fopen(path, "w")) == NULL) {
perror("db_write");
umask(oldmask);
return(-1);
}
fputs("%NAME%\n", fp);
fprintf(fp, "%s\n\n", info->name);
fputs("%VERSION%\n", fp);
fprintf(fp, "%s\n\n", info->version);
fputs("%DESC%\n", fp);
fprintf(fp, "%s\n\n", info->desc);
fputs("%GROUPS%\n", fp);
for(lp = info->groups; lp; lp = lp->next) {
fprintf(fp, "%s\n", (char*)lp->data);
}
fprintf(fp, "\n");
fputs("%URL%\n", fp);
fprintf(fp, "%s\n\n", info->url);
fputs("%LICENSE%\n", fp);
fprintf(fp, "%s\n\n", info->license);
fputs("%ARCH%\n", fp);
fprintf(fp, "%s\n\n", info->arch);
fputs("%BUILDDATE%\n", fp);
fprintf(fp, "%s\n\n", info->builddate);
fputs("%INSTALLDATE%\n", fp);
fprintf(fp, "%s\n\n", info->installdate);
fputs("%PACKAGER%\n", fp);
fprintf(fp, "%s\n\n", info->packager);
fputs("%SIZE%\n", fp);
fprintf(fp, "%ld\n\n", info->size);
fputs("%REASON%\n", fp);
fprintf(fp, "%ld\n\n", info->size);
fclose(fp);
}
/* FILES */
if(inforeq & INFRQ_FILES) {
snprintf(path, PATH_MAX, "%s/files", topdir);
if((fp = fopen(path, "w")) == NULL) {
perror("db_write");
umask(oldmask);
return(-1);
}
fputs("%FILES%\n", fp);
for(lp = info->files; lp; lp = lp->next) {
fprintf(fp, "%s\n", (char*)lp->data);
}
fprintf(fp, "\n");
fputs("%BACKUP%\n", fp);
for(lp = info->backup; lp; lp = lp->next) {
fprintf(fp, "%s\n", (char*)lp->data);
}
fprintf(fp, "\n");
fclose(fp);
}
/* DEPENDS */
if(inforeq & INFRQ_DEPENDS) {
snprintf(path, PATH_MAX, "%s/depends", topdir);
if((fp = fopen(path, "w")) == NULL) {
perror("db_write");
umask(oldmask);
return(-1);
}
fputs("%DEPENDS%\n", fp);
for(lp = info->depends; lp; lp = lp->next) {
fprintf(fp, "%s\n", (char*)lp->data);
}
fprintf(fp, "\n");
fputs("%REQUIREDBY%\n", fp);
for(lp = info->requiredby; lp; lp = lp->next) {
fprintf(fp, "%s\n", (char*)lp->data);
}
fprintf(fp, "\n");
fputs("%CONFLICTS%\n", fp);
for(lp = info->conflicts; lp; lp = lp->next) {
fprintf(fp, "%s\n", (char*)lp->data);
}
fprintf(fp, "\n");
fputs("%PROVIDES%\n", fp);
for(lp = info->provides; lp; lp = lp->next) {
fprintf(fp, "%s\n", (char*)lp->data);
}
fprintf(fp, "\n");
fclose(fp);
}
/* INSTALL */
/* nothing needed here (script is automatically extracted) */
umask(oldmask);
return(0);
}
int db_remove(pmdb_t *db, pmpkg_t *info)
{
char topdir[PATH_MAX];
char file[PATH_MAX];
if(db == NULL || info == NULL) {
return(-1);
}
snprintf(topdir, PATH_MAX, "%s/%s-%s", db->path, info->name, info->version);
/* DESC */
snprintf(file, PATH_MAX, "%s/desc", topdir);
unlink(file);
/* FILES */
snprintf(file, PATH_MAX, "%s/files", topdir);
unlink(file);
/* DEPENDS */
snprintf(file, PATH_MAX, "%s/depends", topdir);
unlink(file);
/* INSTALL */
snprintf(file, PATH_MAX, "%s/install", topdir);
unlink(file);
/* Package directory */
if(rmdir(topdir) == -1) {
return(-1);
}
return(0);
}
PMList *db_find_conflicts(pmdb_t *db, PMList *targets, char *root)
{
PMList *i, *j, *k;
char *filestr = NULL;
char path[PATH_MAX+1];
char *str = NULL;
struct stat buf, buf2;
PMList *conflicts = NULL;
if(db == NULL || targets == NULL || root == NULL) {
return(NULL);
}
/* CHECK 1: check every db package against every target package */
/* XXX: I've disabled the database-against-targets check for now, as the
* many many strcmp() calls slow it down heavily and most of the
* checking is redundant to the targets-against-filesystem check.
* This will be re-enabled if I can improve performance significantly.
*
pmpkg_t *info = NULL;
char *dbstr = NULL;
rewinddir(db->dir);
while((info = db_scan(db, NULL, INFRQ_DESC | INFRQ_FILES)) != NULL) {
for(i = info->files; i; i = i->next) {
if(i->data == NULL) continue;
dbstr = (char*)i->data;
for(j = targets; j; j = j->next) {
pmpkg_t *targ = (pmpkg_t*)j->data;
if(strcmp(info->name, targ->name)) {
for(k = targ->files; k; k = k->next) {
filestr = (char*)k->data;
if(!strcmp(dbstr, filestr)) {
if(rindex(k->data, '/') == filestr+strlen(filestr)-1) {
continue;
}
MALLOC(str, 512);
snprintf(str, 512, "%s: exists in \"%s\" (target) and \"%s\" (installed)", dbstr,
targ->name, info->name);
conflicts = pm_list_add(conflicts, str);
}
}
}
}
}
}*/
/* CHECK 2: check every target against every target */
for(i = targets; i; i = i->next) {
pmpkg_t *p1 = (pmpkg_t*)i->data;
for(j = i; j; j = j->next) {
pmpkg_t *p2 = (pmpkg_t*)j->data;
if(strcmp(p1->name, p2->name)) {
for(k = p1->files; k; k = k->next) {
filestr = k->data;
if(!strcmp(filestr, "._install") || !strcmp(filestr, ".INSTALL")) {
continue;
}
if(rindex(filestr, '/') == filestr+strlen(filestr)-1) {
/* this filename has a trailing '/', so it's a directory -- skip it. */
continue;
}
if(pm_list_is_strin(filestr, p2->files)) {
MALLOC(str, 512);
snprintf(str, 512, "%s: exists in \"%s\" (target) and \"%s\" (target)",
filestr, p1->name, p2->name);
conflicts = pm_list_add(conflicts, str);
}
}
}
}
}
/* CHECK 3: check every target against the filesystem */
for(i = targets; i; i = i->next) {
pmpkg_t *p = (pmpkg_t*)i->data;
pmpkg_t *dbpkg = NULL;
for(j = p->files; j; j = j->next) {
filestr = (char*)j->data;
snprintf(path, PATH_MAX, "%s%s", root, filestr);
if(!stat(path, &buf) && !S_ISDIR(buf.st_mode)) {
int ok = 0;
if(dbpkg == NULL) {
dbpkg = db_scan(db, p->name, INFRQ_DESC | INFRQ_FILES);
}
if(dbpkg && pm_list_is_strin(j->data, dbpkg->files)) {
ok = 1;
}
/* Make sure that the supposedly-conflicting file is not actually just
* a symlink that points to a path that used to exist in the package.
*/
/* Check if any part of the conflicting file's path is a symlink */
if(dbpkg && !ok) {
char str[PATH_MAX];
for(k = dbpkg->files; k; k = k->next) {
snprintf(str, PATH_MAX, "%s%s", root, (char*)k->data);
stat(str, &buf2);
if(buf.st_ino == buf2.st_ino) {
ok = 1;
}
}
}
/* Check if the conflicting file has been moved to another package/target */
if(!ok) {
/* Look at all the targets */
for(k = targets; k && !ok; k = k->next) {
pmpkg_t *p1 = (pmpkg_t *)k->data;
/* As long as they're not the current package */
if(strcmp(p1->name, p->name)) {
pmpkg_t *dbpkg2 = NULL;
dbpkg2 = db_scan(db, p1->name, INFRQ_DESC | INFRQ_FILES);
/* If it used to exist in there, but doesn't anymore */
if(dbpkg2 && !pm_list_is_strin(filestr, p1->files) && pm_list_is_strin(filestr, dbpkg2->files)) {
ok = 1;
}
FREEPKG(dbpkg2);
}
}
}
if(!ok) {
MALLOC(str, 512);
snprintf(str, 512, "%s: exists in filesystem", path);
conflicts = pm_list_add(conflicts, str);
}
}
}
FREEPKG(dbpkg);
}
return(conflicts);
}
/* vim: set ts=2 sw=2 noet: */

60
lib/libalpm/db.h Normal file
View File

@ -0,0 +1,60 @@
/*
* db.h
*
* Copyright (c) 2002-2005 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 _ALPM_DB_H
#define _ALPM_DB_H
#include <dirent.h>
#include "list.h"
#include "package.h"
/* Database entries */
#define INFRQ_NONE 0x00
#define INFRQ_DESC 0x01
#define INFRQ_DEPENDS 0x02
#define INFRQ_FILES 0x04
#define INFRQ_SCRIPLET 0x08
#define INFRQ_ALL 0xFF
/* Database */
typedef struct __pmdb_t {
char *path;
char treename[128];
DIR *dir;
PMList *pkgcache;
PMList *grpcache;
} pmdb_t;
pmdb_t *db_open(char *root, char *dbpath, char *treename);
void db_close(pmdb_t *db);
int db_create(char *root, char *dbpath, char *treename);
void db_rewind(pmdb_t *db);
pmpkg_t *db_scan(pmdb_t *db, char *target, unsigned int inforeq);
int db_read(pmdb_t *db, char *name, unsigned int inforeq, pmpkg_t *info);
int db_write(pmdb_t *db, pmpkg_t *info, unsigned int inforeq);
int db_remove(pmdb_t *db, pmpkg_t *info);
PMList *db_find_conflicts(pmdb_t *db, PMList *targets, char *root);
#endif /* _ALPM_DB_H */
/* vim: set ts=2 sw=2 noet: */

685
lib/libalpm/deps.c Normal file
View File

@ -0,0 +1,685 @@
/*
* deps.c
*
* Copyright (c) 2002-2005 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
/* pacman */
#include "util.h"
#include "log.h"
#include "list.h"
#include "package.h"
#include "db.h"
#include "cache.h"
#include "provide.h"
#include "deps.h"
#include "rpmvercmp.h"
/* Re-order a list of target packages with respect to their dependencies.
*
* Example:
* A depends on C
* B depends on A
* Target order is A,B,C,D
*
* Should be re-ordered to C,A,B,D
*
* This function returns the new PMList* target list.
*
*/
PMList *sortbydeps(PMList *targets)
{
PMList *newtargs = NULL;
PMList *i, *j, *k;
int change = 1;
int numscans = 0;
int numtargs = 0;
int clean = 0;
if(targets == NULL) {
return(NULL);
}
/* count the number of targets */
numtargs = pm_list_count(targets);
while(change) {
change = 0;
if(numscans > numtargs) {
_alpm_log(PM_LOG_FLOW2, "warning: possible dependency cycle detected\n");
change = 0;
continue;
}
newtargs = NULL;
numscans++;
/* run thru targets, moving up packages as necessary */
for(i = targets; i; i = i->next) {
pmpkg_t *p = (pmpkg_t*)i->data;
for(j = p->depends; j; j = j->next) {
pmdepend_t dep;
int found = 0;
pmpkg_t *q = NULL;
splitdep(j->data, &dep);
/* look for dep.name -- if it's farther down in the list, then
* move it up above p
*/
for(k = i->next; k && !found; k = k->next) {
q = (pmpkg_t*)k->data;
if(!strcmp(dep.name, q->name)) {
found = 1;
}
}
if(found) {
if(!pkg_isin(q, newtargs)) {
change = 1;
newtargs = pm_list_add(newtargs, q);
}
}
}
if(!pkg_isin(p, newtargs)) {
newtargs = pm_list_add(newtargs, p);
}
}
if(clean && change) {
/* free up targets -- it's local now */
for(i = targets; i; i = i->next) {
i->data = NULL;
}
pm_list_free(targets);
}
targets = newtargs;
clean = 1;
}
return(targets);
}
/* Returns a PMList* of missing_t pointers.
*
* conflicts are always name only, but dependencies can include versions
* with depmod operators.
*
*/
PMList *checkdeps(pmdb_t *db, unsigned short op, PMList *packages)
{
pmpkg_t *info = NULL;
pmdepend_t depend;
PMList *i, *j, *k;
int cmp;
int found = 0;
PMList *baddeps = NULL;
pmdepmissing_t *miss = NULL;
if(db == NULL) {
return(NULL);
}
if(op == PM_TRANS_TYPE_UPGRADE) {
/* PM_TRANS_TYPE_UPGRADE handles the backwards dependencies, ie, the packages
* listed in the requiredby field.
*/
for(i = packages; i; i = i->next) {
pmpkg_t *tp, *oldpkg;
if(i->data == NULL) {
continue;
}
tp = (pmpkg_t *)i->data;
if((oldpkg = db_scan(db, tp->name, INFRQ_DESC | INFRQ_DEPENDS)) == NULL) {
continue;
}
for(j = oldpkg->requiredby; j; j = j->next) {
char *ver;
pmpkg_t *p;
found = 0;
if((p = db_scan(db, j->data, INFRQ_DESC | INFRQ_DEPENDS)) == NULL) {
/* hmmm... package isn't installed.. */
continue;
}
if(pkg_isin(p, packages)) {
/* this package is also in the upgrade list, so don't worry about it */
continue;
}
for(k = p->depends; k && !found; k = k->next) {
/* find the dependency info in p->depends */
splitdep(k->data, &depend);
if(!strcmp(depend.name, oldpkg->name)) {
found = 1;
}
}
if(found == 0) {
PMList *lp;
/* look for packages that list depend.name as a "provide" */
PMList *provides = _alpm_db_whatprovides(db, depend.name);
if(provides == NULL) {
/* not found */
continue;
}
/* we found an installed package that provides depend.name */
for(lp = provides; lp; lp = lp->next) {
lp->data = NULL;
}
pm_list_free(provides);
}
found = 0;
if(depend.mod == PM_DEP_ANY) {
found = 1;
} else {
/* note that we use the version from the NEW package in the check */
ver = strdup(tp->version);
if(!index(depend.version,'-')) {
char *ptr;
for(ptr = ver; *ptr != '-'; ptr++);
*ptr = '\0';
}
cmp = rpmvercmp(ver, depend.version);
switch(depend.mod) {
case PM_DEP_EQ: found = (cmp == 0); break;
case PM_DEP_GE: found = (cmp >= 0); break;
case PM_DEP_LE: found = (cmp <= 0); break;
}
FREE(ver);
}
if(!found) {
MALLOC(miss, sizeof(pmdepmissing_t));
miss->type = PM_DEP_REQUIRED;
miss->depend.mod = depend.mod;
strncpy(miss->target, p->name, 256);
strncpy(miss->depend.name, depend.name, 256);
strncpy(miss->depend.version, depend.version, 64);
if(!pm_list_is_ptrin(baddeps, miss)) {
baddeps = pm_list_add(baddeps, miss);
}
}
}
pkg_free(oldpkg);
}
}
if(op == PM_TRANS_TYPE_ADD || op == PM_TRANS_TYPE_UPGRADE) {
for(i = packages; i; i = i->next) {
pmpkg_t *tp = i->data;
if(tp == NULL) {
continue;
}
/* CONFLICTS */
for(j = tp->conflicts; j; j = j->next) {
/* check targets against database */
for(k = db_get_pkgcache(db); k; k = k->next) {
pmpkg_t *dp = (pmpkg_t *)k->data;
if(!strcmp(j->data, dp->name)) {
MALLOC(miss, sizeof(pmdepmissing_t));
miss->type = PM_DEP_CONFLICT;
miss->depend.mod = PM_DEP_ANY;
miss->depend.version[0] = '\0';
strncpy(miss->target, tp->name, 256);
strncpy(miss->depend.name, dp->name, 256);
if(!pm_list_is_ptrin(baddeps, miss)) {
baddeps = pm_list_add(baddeps, miss);
}
}
}
/* check targets against targets */
for(k = packages; k; k = k->next) {
pmpkg_t *a = (pmpkg_t *)k->data;
if(!strcmp(a->name, (char *)j->data)) {
MALLOC(miss, sizeof(pmdepmissing_t));
miss->type = PM_DEP_CONFLICT;
miss->depend.mod = PM_DEP_ANY;
miss->depend.version[0] = '\0';
strncpy(miss->target, tp->name, 256);
strncpy(miss->depend.name, a->name, 256);
if(!pm_list_is_ptrin(baddeps, miss)) {
baddeps = pm_list_add(baddeps, miss);
}
}
}
}
/* check database against targets */
for(k = db_get_pkgcache(db); k; k = k->next) {
info = k->data;
for(j = info->conflicts; j; j = j->next) {
if(!strcmp((char *)j->data, tp->name)) {
MALLOC(miss, sizeof(pmdepmissing_t));
miss->type = PM_DEP_CONFLICT;
miss->depend.mod = PM_DEP_ANY;
miss->depend.version[0] = '\0';
strncpy(miss->target, tp->name, 256);
strncpy(miss->depend.name, info->name, 256);
if(!pm_list_is_ptrin(baddeps, miss)) {
baddeps = pm_list_add(baddeps, miss);
}
}
}
}
/* PROVIDES -- check to see if another package already provides what
* we offer
*/
/* XXX: disabled -- we allow multiple packages to provide the same thing.
* list packages in conflicts if they really do conflict.
for(j = tp->provides; j; j = j->next) {
PMList *provs = whatprovides(db, j->data);
for(k = provs; k; k = k->next) {
if(!strcmp(tp->name, k->data->name)) {
// this is the same package -- skip it
continue;
}
// we treat this just like a conflict
MALLOC(miss, sizeof(pmdepmissing_t));
miss->type = CONFLICT;
miss->depend.mod = PM_DEP_ANY;
miss->depend.version[0] = '\0';
strncpy(miss->target, tp->name, 256);
strncpy(miss->depend.name, k->data, 256);
if(!pm_list_is_in(baddeps, miss)) {
baddeps = pm_list_add(baddeps, miss);
}
k->data = NULL;
}
pm_list_free(provs);
}*/
/* DEPENDENCIES -- look for unsatisfied dependencies */
for(j = tp->depends; j; j = j->next) {
/* split into name/version pairs */
splitdep((char *)j->data, &depend);
found = 0;
/* check database for literal packages */
for(k = db_get_pkgcache(db); k && !found; k = k->next) {
pmpkg_t *p = (pmpkg_t *)k->data;
if(!strcmp(p->name, depend.name)) {
if(depend.mod == PM_DEP_ANY) {
/* accept any version */
found = 1;
} else {
char *ver = strdup(p->version);
/* check for a release in depend.version. if it's
* missing remove it from p->version as well.
*/
if(!index(depend.version,'-')) {
char *ptr;
for(ptr = ver; *ptr != '-'; ptr++);
*ptr = '\0';
}
cmp = rpmvercmp(ver, depend.version);
switch(depend.mod) {
case PM_DEP_EQ: found = (cmp == 0); break;
case PM_DEP_GE: found = (cmp >= 0); break;
case PM_DEP_LE: found = (cmp <= 0); break;
}
FREE(ver);
}
}
}
/* check other targets */
for(k = packages; k && !found; k = k->next) {
pmpkg_t *p = (pmpkg_t *)k->data;
/* see if the package names match OR if p provides depend.name */
if(!strcmp(p->name, depend.name) || pm_list_is_strin(depend.name, p->provides)) {
if(depend.mod == PM_DEP_ANY) {
/* accept any version */
found = 1;
} else {
char *ver = strdup(p->version);
/* check for a release in depend.version. if it's
* missing remove it from p->version as well.
*/
if(!index(depend.version,'-')) {
char *ptr;
for(ptr = ver; *ptr != '-'; ptr++);
*ptr = '\0';
}
cmp = rpmvercmp(ver, depend.version);
switch(depend.mod) {
case PM_DEP_EQ: found = (cmp == 0); break;
case PM_DEP_GE: found = (cmp >= 0); break;
case PM_DEP_LE: found = (cmp <= 0); break;
}
FREE(ver);
}
}
}
/* check database for provides matches */
if(!found){
PMList *lp;
k = _alpm_db_whatprovides(db, depend.name);
if(k) {
/* grab the first one (there should only really be one, anyway) */
pmpkg_t *p = db_scan(db, ((pmpkg_t *)k->data)->name, INFRQ_DESC);
if(p == NULL) {
/* wtf */
fprintf(stderr, "data error: %s supposedly provides %s, but it was not found in db\n",
((pmpkg_t *)k->data)->name, depend.name);
for(lp = k; lp; lp = lp->next) {
lp->data = NULL;
}
pm_list_free(k);
continue;
}
if(depend.mod == PM_DEP_ANY) {
/* accept any version */
found = 1;
} else {
char *ver = strdup(p->version);
/* check for a release in depend.version. if it's
* missing remove it from p->version as well.
*/
if(!index(depend.version,'-')) {
char *ptr;
for(ptr = ver; *ptr != '-'; ptr++);
*ptr = '\0';
}
cmp = rpmvercmp(ver, depend.version);
switch(depend.mod) {
case PM_DEP_EQ: found = (cmp == 0); break;
case PM_DEP_GE: found = (cmp >= 0); break;
case PM_DEP_LE: found = (cmp <= 0); break;
}
FREE(ver);
}
}
for(lp = k; lp; lp = lp->next) {
lp->data = NULL;
}
pm_list_free(k);
}
/* else if still not found... */
if(!found) {
MALLOC(miss, sizeof(pmdepmissing_t));
miss->type = PM_DEP_DEPEND;
miss->depend.mod = depend.mod;
strncpy(miss->target, tp->name, 256);
strncpy(miss->depend.name, depend.name, 256);
strncpy(miss->depend.version, depend.version, 64);
if(!pm_list_is_ptrin(baddeps, miss)) {
baddeps = pm_list_add(baddeps, miss);
}
}
}
}
} else if(op == PM_TRANS_TYPE_REMOVE) {
/* check requiredby fields */
for(i = packages; i; i = i->next) {
pmpkg_t *tp;
if(i->data == NULL) {
continue;
}
tp = (pmpkg_t*)i->data;
for(j = tp->requiredby; j; j = j->next) {
if(!pm_list_is_strin((char *)j->data, packages)) {
MALLOC(miss, sizeof(pmdepmissing_t));
miss->type = PM_DEP_REQUIRED;
miss->depend.mod = PM_DEP_ANY;
miss->depend.version[0] = '\0';
strncpy(miss->target, tp->name, 256);
strncpy(miss->depend.name, (char *)j->data, 256);
if(!pm_list_is_ptrin(baddeps, miss)) {
baddeps = pm_list_add(baddeps, miss);
}
}
}
}
}
return(baddeps);
}
void splitdep(char *depstr, pmdepend_t *depend)
{
char *str = NULL;
char *ptr = NULL;
if(depstr == NULL) {
return;
}
str = strdup(depstr);
if((ptr = strstr(str, ">="))) {
depend->mod = PM_DEP_GE;
} else if((ptr = strstr(str, "<="))) {
depend->mod = PM_DEP_LE;
} else if((ptr = strstr(str, "="))) {
depend->mod = PM_DEP_EQ;
} else {
/* no version specified - accept any */
depend->mod = PM_DEP_ANY;
strncpy(depend->name, str, sizeof(depend->name));
strncpy(depend->version, "", sizeof(depend->version));
}
if(ptr == NULL) {
FREE(str);
return;
}
*ptr = '\0';
strncpy(depend->name, str, sizeof(depend->name));
ptr++;
if(depend->mod != PM_DEP_EQ) {
ptr++;
}
strncpy(depend->version, ptr, sizeof(depend->version));
FREE(str);
return;
}
/* return a new PMList target list containing all packages in the original
* target list, as well as all their un-needed dependencies. By un-needed,
* I mean dependencies that are *only* required for packages in the target
* list, so they can be safely removed. This function is recursive.
*/
PMList* removedeps(pmdb_t *db, PMList *targs)
{
PMList *i, *j, *k;
PMList *newtargs = targs;
if(db == NULL) {
return(newtargs);
}
for(i = targs; i; i = i->next) {
pmpkg_t *pkg = (pmpkg_t*)i->data;
for(j = pkg->depends; j; j = j->next) {
pmdepend_t depend;
pmpkg_t *dep;
int needed = 0;
splitdep(j->data, &depend);
dep = db_scan(db, depend.name, INFRQ_DESC | INFRQ_DEPENDS);
if(pkg_isin(dep, targs)) {
continue;
}
/* see if it was explicitly installed */
if(dep->reason == PM_PKG_REASON_EXPLICIT) {
/* ORE
vprint("excluding %s -- explicitly installed\n", dep->name);*/
needed = 1;
}
/* see if other packages need it */
for(k = dep->requiredby; k && !needed; k = k->next) {
pmpkg_t *dummy = db_scan(db, k->data, INFRQ_DESC);
if(!pkg_isin(dummy, targs)) {
needed = 1;
}
}
if(!needed) {
/* add it to the target list */
pkg_free(dep);
dep = db_scan(db, depend.name, INFRQ_ALL);
newtargs = pm_list_add(newtargs, dep);
newtargs = removedeps(db, newtargs);
}
}
}
return(newtargs);
}
/* populates *list with packages that need to be installed to satisfy all
* dependencies (recursive) for *syncpkg->pkg
*
* make sure *list and *trail are already initialized
*/
int resolvedeps(pmdb_t *local, PMList *databases, pmsync_t *sync, PMList *list, PMList *trail, PMList **data)
{
PMList *i, *j;
PMList *targ = NULL;
PMList *deps = NULL;
targ = pm_list_add(targ, sync->spkg);
deps = checkdeps(local, PM_TRANS_TYPE_ADD, targ);
targ->data = NULL;
pm_list_free(targ);
if(deps == NULL) {
return(0);
}
for(i = deps; i; i = i->next) {
int found = 0;
pmdepmissing_t *miss = i->data;
/* XXX: conflicts are now treated specially in the _add and _sync functions */
/*if(miss->type == CONFLICT) {
fprintf(stderr, "error: cannot resolve dependencies for \"%s\":\n", miss->target);
fprintf(stderr, " %s conflicts with %s\n", miss->target, miss->depend.name);
return(1);
} else*/
if(miss->type == PM_DEP_DEPEND) {
pmsync_t *sync = NULL;
/* find the package in one of the repositories */
/* check literals */
for(j = databases; !sync && j; j = j->next) {
PMList *k;
pmdb_t *dbs = j->data;
for(k = db_get_pkgcache(dbs); !sync && k; k = k->next) {
pmpkg_t *pkg = k->data;
if(!strcmp(miss->depend.name, pkg->name)) {
sync = sync_new(PM_SYSUPG_DEPEND, NULL, k->data);
if(sync == NULL) {
pm_errno = PM_ERR_MEMORY;
goto error;
}
/* ORE
sync->pkg->reason = PM_PKG_REASON_DEPEND;*/
}
}
}
/* check provides */
/* ORE
for(j = databases; !s && j; j = j->next) {
PMList *provides;
provides = _alpm_db_whatprovides(j->data, miss->depend.name);
if(provides) {
s = sync_new(PM_SYSUPG_DEPEND, NULL, !!!provides->data!!!);
if(s == NULL) {
pm_errno = PM_ERR_MEMORY;
FREELIST(deps);
return(-1);
}
sync->pkg->reason = PM_PKG_REASON_DEPEND;
}
FREELIST(provides);
}*/
if(sync == NULL) {
pmdepmissing_t *m = (pmdepmissing_t *)malloc(sizeof(pmdepmissing_t));
if(m == NULL) {
/* ORE
Free memory before leaving */
pm_errno = PM_ERR_MEMORY;
goto error;
}
*m = *(pmdepmissing_t *)i->data;
*data = pm_list_add(*data, m);
continue;
}
if(*data) {
/* there is at least an unresolvable dep... so we only
* continue to get the whole list of unresolvable deps */
continue;
}
found = 0;
for(j = list; j && !found; j = j->next) {
pmsync_t *tmp = j->data;
if(tmp && !strcmp(tmp->spkg->name, sync->spkg->name)) {
found = 1;
}
}
if(found) {
/* this dep is already in the target list */
FREE(sync);
continue;
}
_alpm_log(PM_LOG_FLOW2, "resolving %s", sync->spkg->name);
found = 0;
for(j = trail; j; j = j->next) {
pmsync_t *tmp = j->data;
if(tmp && !strcmp(tmp->spkg->name, sync->spkg->name)) {
found = 1;
}
}
if(!found) {
trail = pm_list_add(trail, sync);
if(resolvedeps(local, databases, sync, list, trail, data)) {
goto error;
}
_alpm_log(PM_LOG_FLOW2, "adding %s-%s", sync->spkg->name, sync->spkg->version);
list = pm_list_add(list, sync);
} else {
/* cycle detected -- skip it */
_alpm_log(PM_LOG_FLOW2, "dependency cycle detected: %s", sync->spkg->name);
FREE(sync);
}
}
}
FREELIST(deps);
if(*data) {
pm_errno = PM_ERR_UNRESOLVABLE_DEPS;
return(-1);
}
return(0);
error:
FREELIST(deps);
return(-1);
}
/* vim: set ts=2 sw=2 noet: */

35
lib/libalpm/deps.h Normal file
View File

@ -0,0 +1,35 @@
/*
* deps.h
*
* Copyright (c) 2002-2005 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 _ALPM_DEPS_H
#define _ALPM_DEPS_H
#include "db.h"
#include "sync.h"
PMList *sortbydeps(PMList *targets);
PMList *checkdeps(pmdb_t *db, unsigned short op, PMList *packages);
void splitdep(char *depstr, pmdepend_t *depend);
PMList *removedeps(pmdb_t *db, PMList *targs);
int resolvedeps(pmdb_t *local, PMList *databases, pmsync_t *sync, PMList *list, PMList *trail, PMList **data);
#endif /* _ALPM_DEPS_H */
/* vim: set ts=2 sw=2 noet: */

90
lib/libalpm/error.c Normal file
View File

@ -0,0 +1,90 @@
/*
* error.c
*
* Copyright (c) 2002-2005 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 "alpm.h"
char *alpm_strerror(int err)
{
switch(err) {
/* System */
case PM_ERR_NOT_A_FILE:
return "could not find or read file";
/* Interface */
case PM_ERR_HANDLE_NULL:
return "library not initialized";
case PM_ERR_HANDLE_NOT_NULL:
return "library already initialized";
case PM_ERR_WRONG_ARGS:
return "wrong or NULL argument";
/* Databases */
case PM_ERR_DB_OPEN:
return "could not open database";
case PM_ERR_DB_CREATE:
return "could not create database";
case PM_ERR_DB_NULL:
return "database not initialized";
case PM_ERR_DB_NOT_NULL:
return "database already registered";
case PM_ERR_DB_NOT_FOUND:
return "could not find database";
/* Configuration */
case PM_ERR_OPT_LOGFILE:
case PM_ERR_OPT_DBPATH:
case PM_ERR_OPT_SYNCDB:
case PM_ERR_OPT_USESYSLOG:
return "could not set parameter";
/* Transactions */
case PM_ERR_TRANS_NULL:
return "transaction not initialized";
case PM_ERR_TRANS_NOT_NULL:
return "transaction already initialized";
case PM_ERR_TRANS_DUP_TARGET:
return "duplicated target";
case PM_ERR_TRANS_INITIALIZED:
return "transaction already initialized";
case PM_ERR_TRANS_NOT_INITIALIZED:
return "transaction not initialized";
/* Packages */
case PM_ERR_PKG_NOT_FOUND:
return "could not find or read package";
case PM_ERR_PKG_INVALID:
return "invalid or corrupted package";
case PM_ERR_PKG_INSTALLED:
return "package already installed";
case PM_ERR_PKG_CANT_FRESH:
return "package not installed or lesser version";
case PM_ERR_INVALID_NAME:
return "package name is not valid";
/* Dependencies */
case PM_ERR_UNSATISFIED_DEPS:
return "could not satisfy dependencies";
case PM_ERR_CONFLICTING_DEPS:
return "conflicting dependencies";
case PM_ERR_UNRESOLVABLE_DEPS:
return "could not resolve dependencies";
case PM_ERR_FILE_CONFLICTS:
return "conflicting files";
default:
return "unexpected error";
}
}
/* vim: set ts=2 sw=2 noet: */

30
lib/libalpm/error.h Normal file
View File

@ -0,0 +1,30 @@
/*
* error.h
*
* Copyright (c) 2002-2005 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 _ALPM_ERROR_H
#define _ALPM_ERROR_H
#include "alpm.h"
#define PM_RET_ERR(err, ret) do { pm_errno = (err); return(ret); } while(0)
#endif /* _ALPM_ERROR_H */
/* vim: set ts=2 sw=2 noet: */

67
lib/libalpm/group.c Normal file
View File

@ -0,0 +1,67 @@
/*
* group.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* pacman */
#include "util.h"
#include "group.h"
pmgrp_t *grp_new()
{
pmgrp_t* grp = NULL;
grp = (pmgrp_t *)malloc(sizeof(pmgrp_t));
if(grp == NULL) {
return(NULL);
}
grp->name[0] = '\0';
grp->packages = NULL;
return(grp);
}
void grp_free(pmgrp_t *grp)
{
if(grp == NULL) {
return;
}
FREELIST(grp->packages);
FREE(grp);
return;
}
/* Helper function for sorting groups
*/
int grp_cmp(const void *g1, const void *g2)
{
pmgrp_t *grp1 = (pmgrp_t *)g1;
pmgrp_t *grp2 = (pmgrp_t *)g2;
return(strcmp(grp1->name, grp2->name));
}
/* vim: set ts=2 sw=2 noet: */

48
lib/libalpm/group.h Normal file
View File

@ -0,0 +1,48 @@
/*
* group.h
*
* Copyright (c) 2002-2005 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 _ALPM_GROUP_H
#define _ALPM_GROUP_H
#include "list.h"
/* Groups structure */
typedef struct __pmgrp_t {
char name[256];
PMList *packages; /* List of strings */
} pmgrp_t;
#define FREEGRP(p) do { if(p) { grp_free(p); p = NULL; } } while(0)
#define FREELISTGRPS(p) do { \
PMList *i; \
for(i = p; i; i = i->next) { \
FREEGRP(i->data); \
} \
FREELIST(p); \
} while(0)
pmgrp_t *grp_new();
void grp_free(pmgrp_t *grp);
int grp_cmp(const void *g1, const void *g2);
#endif /* _ALPM_GROUP_H */
/* vim: set ts=2 sw=2 noet: */

229
lib/libalpm/handle.c Normal file
View File

@ -0,0 +1,229 @@
/*
* handle.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <sys/types.h>
#include <stdarg.h>
#include <syslog.h>
/* pacman */
#include "util.h"
#include "log.h"
#include "list.h"
#include "error.h"
#include "trans.h"
#include "alpm.h"
#include "handle.h"
/* log */
extern alpm_cb_log __pm_logcb;
extern unsigned char __pm_logmask;
pmhandle_t *handle_new()
{
pmhandle_t *handle;
handle = (pmhandle_t *)malloc(sizeof(pmhandle_t));
if(handle == NULL) {
PM_RET_ERR(PM_ERR_MEMORY, NULL);
}
/* see if we're root or not */
handle->uid = geteuid();
if(!handle->uid && getenv("FAKEROOTKEY")) {
/* fakeroot doesn't count, we're non-root */
handle->uid = 99;
}
/* see if we're root or not (fakeroot does not count) */
if(getuid() == 0 && !getenv("FAKEROOTKEY")) {
handle->access = PM_ACCESS_RW;
} else {
handle->access = PM_ACCESS_RO;
}
handle->trans = NULL;
handle->db_local = NULL;
handle->dbs_sync = NULL;
handle->logfd = NULL;
handle->root = NULL;
handle->dbpath = NULL;
handle->logfile = NULL;
handle->noupgrade = NULL;
handle->ignorepkg = NULL;
handle->usesyslog = 0;
return(handle);
}
int handle_free(pmhandle_t *handle)
{
ASSERT(handle != NULL, PM_RET_ERR(PM_ERR_HANDLE_NULL, -1));
/* close logfiles */
if(handle->logfd) {
fclose(handle->logfd);
handle->logfd = NULL;
}
if(handle->usesyslog) {
handle->usesyslog = 0;
closelog();
}
/* free memory */
FREETRANS(handle->trans);
FREE(handle->root);
FREE(handle->dbpath);
FREE(handle->logfile);
FREELIST(handle->dbs_sync);
FREELIST(handle->noupgrade);
FREELIST(handle->ignorepkg);
free(handle);
return(0);
}
int handle_set_option(pmhandle_t *handle, unsigned char val, unsigned long data)
{
PMList *lp;
char str[PATH_MAX];
/* Sanity checks */
ASSERT(handle != NULL, PM_RET_ERR(PM_ERR_HANDLE_NULL, -1));
switch(val) {
case PM_OPT_DBPATH:
if(handle->db_local) {
PM_RET_ERR(PM_ERR_DB_NOT_NULL, -1);
}
for(lp = handle->dbs_sync; lp; lp = lp->next) {
if(lp->data) {
PM_RET_ERR(PM_ERR_DB_NOT_NULL, -1);
}
}
if(handle->trans && handle->trans->state != STATE_IDLE) {
PM_RET_ERR(PM_ERR_TRANS_INITIALIZED, -1);
}
strncpy(str, ((char *)data) ? (char *)data : PACDBPATH, PATH_MAX);
handle->dbpath = strdup(str);
_alpm_log(PM_LOG_FLOW2, "PM_OPT_DBPATH set to '%s'", handle->dbpath);
break;
case PM_OPT_LOGFILE:
if((char *)data == NULL || getuid() != 0) {
return(0);
}
if(handle->logfile) {
FREE(handle->logfile);
}
if(handle->logfd) {
if(fclose(handle->logfd) != 0) {
handle->logfd = NULL;
PM_RET_ERR(PM_ERR_OPT_LOGFILE, -1);
}
handle->logfd = NULL;
}
if((handle->logfd = fopen((char *)data, "a")) == NULL) {
_alpm_log(PM_LOG_ERROR, "can't open log file %s", (char *)data);
PM_RET_ERR(PM_ERR_OPT_LOGFILE, -1);
}
handle->logfile = strdup((char *)data);
_alpm_log(PM_LOG_FLOW2, "PM_OPT_LOGFILE set to '%s'", (char *)data);
break;
case PM_OPT_NOUPGRADE:
if((char *)data && strlen((char *)data) != 0) {
handle->noupgrade = pm_list_add(handle->noupgrade, strdup((char *)data));
_alpm_log(PM_LOG_FLOW2, "'%s' added to PM_OPT_NOUPGRADE", (char *)data);
} else {
FREELIST(handle->noupgrade);
_alpm_log(PM_LOG_FLOW2, "PM_OPT_NOUPGRADE flushed");
}
break;
case PM_OPT_IGNOREPKG:
if((char *)data && strlen((char *)data) != 0) {
handle->ignorepkg = pm_list_add(handle->ignorepkg, strdup((char *)data));
_alpm_log(PM_LOG_FLOW2, "'%s' added to PM_OPT_IGNOREPKG", (char *)data);
} else {
FREELIST(handle->ignorepkg);
_alpm_log(PM_LOG_FLOW2, "PM_OPT_IGNOREPKG flushed");
}
break;
case PM_OPT_USESYSLOG:
if(data != 0 && data != 1) {
PM_RET_ERR(PM_ERR_OPT_USESYSLOG, -1);
}
if(handle->usesyslog == data) {
return(0);
}
if(handle->usesyslog) {
closelog();
} else {
openlog("alpm", 0, LOG_USER);
}
handle->usesyslog = (unsigned short)data;
_alpm_log(PM_LOG_FLOW2, "PM_OPT_USESYSLOG set to '%d'", handle->usesyslog);
break;
case PM_OPT_LOGCB:
__pm_logcb = (alpm_cb_log)data;
break;
case PM_OPT_LOGMASK:
__pm_logmask = (unsigned char)data;
_alpm_log(PM_LOG_FLOW2, "PM_OPT_LOGMASK set to '%02x'", (unsigned char)data);
break;
default:
PM_RET_ERR(PM_ERR_WRONG_ARGS, -1);
}
return(0);
}
int handle_get_option(pmhandle_t *handle, unsigned char val, long *data)
{
/* Sanity checks */
ASSERT(handle != NULL, PM_RET_ERR(PM_ERR_HANDLE_NULL, -1));
switch(val) {
case PM_OPT_ROOT: *data = (long)handle->root; break;
case PM_OPT_DBPATH: *data = (long)handle->dbpath; break;
case PM_OPT_LOCALDB: *data = (long)handle->db_local; break;
case PM_OPT_SYNCDB: *data = (long)handle->dbs_sync; break;
case PM_OPT_LOGFILE: *data = (long)handle->logfile; break;
case PM_OPT_NOUPGRADE: *data = (long)handle->noupgrade; break;
case PM_OPT_IGNOREPKG: *data = (long)handle->ignorepkg; break;
case PM_OPT_USESYSLOG: *data = handle->usesyslog; break;
case PM_OPT_LOGCB: *data = (long)__pm_logcb; break;
case PM_OPT_LOGMASK: *data = __pm_logmask; break;
default:
PM_RET_ERR(PM_ERR_WRONG_ARGS, -1);
break;
}
return(0);
}
/* vim: set ts=2 sw=2 noet: */

63
lib/libalpm/handle.h Normal file
View File

@ -0,0 +1,63 @@
/*
* handle.h
*
* Copyright (c) 2002-2005 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 _ALPM_HANDLE_H
#define _ALPM_HANDLE_H
#include "list.h"
#include "db.h"
#include "trans.h"
#include "alpm.h"
#define PACROOT "/"
#define PACDBPATH "var/lib/pacman"
#define PACLOCK "/tmp/pacman.lck"
typedef enum __pmaccess_t {
PM_ACCESS_RO,
PM_ACCESS_RW
} pmaccess_t;
typedef struct __pmhandle_t {
pmaccess_t access;
uid_t uid;
pmdb_t *db_local;
PMList *dbs_sync; /* List of (pmdb_t *) */
FILE *logfd;
pmtrans_t *trans;
/* parameters */
char *root;
char *dbpath;
char *logfile;
PMList *noupgrade; /* List of strings */
PMList *ignorepkg; /* List of strings */
unsigned char usesyslog;
} pmhandle_t;
#define FREEHANDLE(p) do { if (p) { handle_free(p); p = NULL; } } while (0)
pmhandle_t *handle_new();
int handle_free(pmhandle_t *handle);
int handle_set_option(pmhandle_t *handle, unsigned char val, unsigned long data);
int handle_get_option(pmhandle_t *handle, unsigned char val, long *data);
#endif /* _ALPM_HANDLE_H */
/* vim: set ts=2 sw=2 noet: */

210
lib/libalpm/list.c Normal file
View File

@ -0,0 +1,210 @@
/*
* list.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/* pacman */
#include "list.h"
PMList* pm_list_new()
{
PMList *list = NULL;
list = (PMList *)malloc(sizeof(PMList));
if(list == NULL) {
return(NULL);
}
list->data = NULL;
list->prev = NULL;
list->next = NULL;
return(list);
}
void pm_list_free(PMList *list)
{
if(list == NULL) {
return;
}
if(list->data != NULL) {
free(list->data);
list->data = NULL;
}
if(list->next != NULL) {
pm_list_free(list->next);
}
free(list);
return;
}
PMList* pm_list_add(PMList *list, void *data)
{
PMList *ptr, *lp;
ptr = list;
if(ptr == NULL) {
ptr = pm_list_new();
}
lp = pm_list_last(ptr);
if(lp == ptr && lp->data == NULL) {
/* nada */
} else {
lp->next = pm_list_new();
if(lp->next == NULL) {
return(NULL);
}
lp->next->prev = lp;
lp = lp->next;
}
lp->data = data;
return(ptr);
}
/* Add items to a list in sorted order. Use the given comparision func to
* determine order.
*/
PMList* pm_list_add_sorted(PMList *list, void *data, pm_fn_cmp fn)
{
PMList *add;
PMList *prev = NULL;
PMList *iter = list;
add = pm_list_new();
add->data = data;
/* Find insertion point. */
while(iter) {
if(fn(add->data, iter->data) <= 0) break;
prev = iter;
iter = iter->next;
}
/* Insert node before insertion point. */
add->prev = prev;
add->next = iter;
if(iter != NULL) {
/* Not at end. */
iter->prev = add;
}
if(prev != NULL) {
/* In middle. */
prev->next = add;
} else {
/* Start or empty, new list head. */
list = add;
}
return(list);
}
/* Remove an item in a list. Use the given comparaison function to find the
* item.
* If found, 'ptr' is set to point to the removed element, so that the caller
* can free it. Otherwise, ptr is NULL.
* Return the new list (without the removed element).
*/
PMList *_alpm_list_remove(PMList *list, void *data, pm_fn_cmp fn, void **ptr)
{
PMList *i = list;
while(i) {
if(fn(data, i->data) == 0) {
break;
}
i = i->next;
}
if(ptr) {
*ptr = NULL;
}
if(i) {
/* we found a matching item */
if(i->next) {
i->next->prev = i->prev;
}
if(i->prev) {
i->prev->next = i->next;
}
if(i == list) {
/* The item found is the first in the chain,
* so we move the header to the next element.
*/
list = list->next;
}
if(ptr) {
*ptr = i->data;
}
free(i);
}
return(list);
}
int pm_list_count(PMList *list)
{
int i;
PMList *lp;
for(lp = list, i = 0; lp; lp = lp->next, i++);
return(i);
}
int pm_list_is_ptrin(PMList *haystack, void *needle)
{
PMList *lp;
for(lp = haystack; lp; lp = lp->next) {
if(lp->data == needle) {
return(1);
}
}
return(0);
}
/* Test for existence of a string in a PMList
*/
PMList *pm_list_is_strin(char *needle, PMList *haystack)
{
PMList *lp;
for(lp = haystack; lp; lp = lp->next) {
if(lp->data && !strcmp(lp->data, needle)) {
return(lp);
}
}
return(NULL);
}
PMList* pm_list_last(PMList *list)
{
PMList *ptr;
for(ptr = list; ptr && ptr->next; ptr = ptr->next);
return(ptr);
}
/* vim: set ts=2 sw=2 noet: */

50
lib/libalpm/list.h Normal file
View File

@ -0,0 +1,50 @@
/*
* list.h
*
* Copyright (c) 2002-2005 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 _ALPM_LIST_H
#define _ALPM_LIST_H
/* Chained list struct */
typedef struct __pmlist_t {
void *data;
struct __pmlist_t *prev;
struct __pmlist_t *next;
} pmlist_t;
typedef struct __pmlist_t PMList;
#define FREELIST(p) do { if(p) { pm_list_free(p); p = NULL; } } while(0)
/* Sort comparison callback function declaration */
typedef int (*pm_fn_cmp) (const void *, const void *);
PMList *pm_list_new();
void pm_list_free(PMList *list);
PMList *pm_list_add(PMList *list, void *data);
PMList *pm_list_add_sorted(PMList *list, void *data, pm_fn_cmp fn);
PMList *_alpm_list_remove(PMList *list, void *data, pm_fn_cmp fn, void **ptr);
int pm_list_count(PMList *list);
int pm_list_is_ptrin(PMList *haystack, void *needle);
PMList *pm_list_is_strin(char *needle, PMList *haystack);
PMList *pm_list_last(PMList *list);
#endif /* _ALPM_LIST_H */
/* vim: set ts=2 sw=2 noet: */

52
lib/libalpm/log.c Normal file
View File

@ -0,0 +1,52 @@
/*
* log.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
/* pacman */
#include "log.h"
/* Internal library log mechanism */
alpm_cb_log __pm_logcb = NULL;
unsigned char __pm_logmask = 0;
void _alpm_log(unsigned char flag, char *fmt, ...)
{
char str[256];
va_list args;
if(__pm_logcb == NULL) {
return;
}
if(flag & __pm_logmask) {
va_start(args, fmt);
vsnprintf(str, 256, fmt, args);
va_end(args);
__pm_logcb(flag, str);
}
}
/* vim: set ts=2 sw=2 noet: */

32
lib/libalpm/log.h Normal file
View File

@ -0,0 +1,32 @@
/*
* log.h
*
* Copyright (c) 2002-2005 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 _ALPM_LOG_H
#define _ALPM_LOG_H
typedef void (*alpm_cb_log)(unsigned short, char *);
void _alpm_log(unsigned char flag, char *fmt, ...);
int _alpm_log_action(unsigned char usesyslog, FILE *f, char *fmt, ...);
#endif /* _ALPM_LOG_H */
/* vim: set ts=2 sw=2 noet: */

338
lib/libalpm/md5.c Normal file
View File

@ -0,0 +1,338 @@
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#include "md5.h"
/* Constants for MD5Transform routine.
*/
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static void MD5Transform(UINT4 [4], unsigned char [64]);
static void Encode(unsigned char *, UINT4 *, unsigned int);
static void Decode(UINT4 *, unsigned char *, unsigned int);
static void MD5_memcpy(POINTER, POINTER, unsigned int);
static void MD5_memset(POINTER, int, unsigned int);
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void MD5Init (context)
MD5_CTX *context; /* context */
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the
context.
*/
void MD5Update (context, input, inputLen)
MD5_CTX *context; /* context */
unsigned char *input; /* input block */
unsigned int inputLen; /* length of input block */
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
MD5_memcpy
((POINTER)&context->buffer[index], (POINTER)input, partLen);
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
MD5_memcpy
((POINTER)&context->buffer[index], (POINTER)&input[i],
inputLen-i);
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
void MD5Final (digest, context)
unsigned char digest[16]; /* message digest */
MD5_CTX *context; /* context */
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.
*/
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, PADDING, padLen);
/* Append length (before padding) */
MD5Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)context, 0, sizeof (*context));
}
/* MD5 basic transformation. Transforms state based on block.
*/
static void MD5Transform (state, block)
UINT4 state[4];
unsigned char block[64];
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)x, 0, sizeof (x));
}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
a multiple of 4.
*/
static void Encode (output, input, len)
unsigned char *output;
UINT4 *input;
unsigned int len;
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
a multiple of 4.
*/
static void Decode (output, input, len)
UINT4 *output;
unsigned char *input;
unsigned int len;
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
/* Note: Replace "for loop" with standard memcpy if possible.
*/
static void MD5_memcpy (output, input, len)
POINTER output;
POINTER input;
unsigned int len;
{
unsigned int i;
for (i = 0; i < len; i++)
output[i] = input[i];
}
/* Note: Replace "for loop" with standard memset if possible.
*/
static void MD5_memset (output, value, len)
POINTER output;
int value;
unsigned int len;
{
unsigned int i;
for (i = 0; i < len; i++)
((char *)output)[i] = (char)value;
}
/* vim: set ts=2 sw=2 noet: */

51
lib/libalpm/md5.h Normal file
View File

@ -0,0 +1,51 @@
/* MD5.H - header file for MD5C.C
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;
/* UINT2 defines a two byte word */
typedef unsigned short int UINT2;
/* UINT4 defines a four byte word */
typedef unsigned long int UINT4;
/* MD5 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
void MD5Init(MD5_CTX *);
void MD5Update(MD5_CTX *, unsigned char *, unsigned int);
void MD5Final(unsigned char [16], MD5_CTX *);
char* MDFile(char *);
void MDPrint(unsigned char [16]);
/* vim: set ts=2 sw=2 noet: */

81
lib/libalpm/md5driver.c Normal file
View File

@ -0,0 +1,81 @@
/* MD5DRIVER.C - taken and modified from MDDRIVER.C (license below) */
/* for use in pacman. */
/*********************************************************************/
/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
rights reserved.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
/* The following makes MD default to MD5 if it has not already been
defined with C compiler flags.
*/
#define MD MD5
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "md5.h"
/* Length of test block, number of test blocks.
*/
#define TEST_BLOCK_LEN 1000
#define TEST_BLOCK_COUNT 1000
#define MD_CTX MD5_CTX
#define MDInit MD5Init
#define MDUpdate MD5Update
#define MDFinal MD5Final
char* MDFile(char *filename)
{
FILE *file;
MD_CTX context;
int len;
unsigned char buffer[1024], digest[16];
if((file = fopen(filename, "rb")) == NULL) {
printf ("%s can't be opened\n", filename);
} else {
char *ret;
int i;
MDInit(&context);
while((len = fread(buffer, 1, 1024, file))) {
MDUpdate(&context, buffer, len);
}
MDFinal(digest, &context);
fclose(file);
/*printf("MD5 (%s) = ", filename);
MDPrint(digest);
printf("\n");*/
ret = (char*)malloc(33);
ret[0] = '\0';
for(i = 0; i < 16; i++) {
sprintf(ret, "%s%02x", ret, digest[i]);
}
return(ret);
}
return(NULL);
}
/* Prints a message digest in hexadecimal.
*/
void MDPrint(unsigned char digest[16])
{
unsigned int i;
for (i = 0; i < 16; i++)
printf ("%02x", digest[i]);
}
/* vim: set ts=2 sw=2 noet: */

342
lib/libalpm/package.c Normal file
View File

@ -0,0 +1,342 @@
/*
* package.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <fcntl.h>
#include <string.h>
#include <libtar.h>
#include <zlib.h>
/* pacman */
#include "log.h"
#include "util.h"
#include "error.h"
#include "list.h"
#include "package.h"
pmpkg_t *pkg_new()
{
pmpkg_t* pkg = NULL;
MALLOC(pkg, sizeof(pmpkg_t));
pkg->name[0] = '\0';
pkg->version[0] = '\0';
pkg->desc[0] = '\0';
pkg->url[0] = '\0';
pkg->license[0] = '\0';
pkg->builddate[0] = '\0';
pkg->installdate[0] = '\0';
pkg->packager[0] = '\0';
pkg->md5sum[0] = '\0';
pkg->arch[0] = '\0';
pkg->size = 0;
pkg->scriptlet = 0;
pkg->force = 0;
pkg->reason = PM_PKG_REASON_EXPLICIT;
pkg->requiredby = NULL;
pkg->conflicts = NULL;
pkg->files = NULL;
pkg->backup = NULL;
pkg->depends = NULL;
pkg->groups = NULL;
pkg->provides = NULL;
pkg->replaces = NULL;
/* internal */
pkg->origin = 0;
pkg->data = NULL;
pkg->infolevel = 0;
return(pkg);
}
void pkg_free(pmpkg_t *pkg)
{
if(pkg == NULL) {
return;
}
FREELIST(pkg->files);
FREELIST(pkg->backup);
FREELIST(pkg->depends);
FREELIST(pkg->conflicts);
FREELIST(pkg->requiredby);
FREELIST(pkg->groups);
FREELIST(pkg->provides);
FREELIST(pkg->replaces);
if(pkg->origin == PKG_FROM_FILE) {
FREE(pkg->data);
}
free(pkg);
return;
}
/* Parses the package description file for the current package
*
* Returns: 0 on success, 1 on error
*
*/
static int parse_descfile(char *descfile, pmpkg_t *info, int output)
{
FILE* fp = NULL;
char line[PATH_MAX+1];
char* ptr = NULL;
char* key = NULL;
int linenum = 0;
if((fp = fopen(descfile, "r")) == NULL) {
_alpm_log(PM_LOG_ERROR, "could not open file %s", descfile);
return(-1);
}
while(!feof(fp)) {
fgets(line, PATH_MAX, fp);
linenum++;
_alpm_strtrim(line);
if(strlen(line) == 0 || line[0] == '#') {
continue;
}
if(output) {
printf("%s\n", line);
}
ptr = line;
key = strsep(&ptr, "=");
if(key == NULL || ptr == NULL) {
fprintf(stderr, "%s: syntax error in description file line %d\n",
info->name[0] != '\0' ? info->name : "error", linenum);
} else {
_alpm_strtrim(key);
key = _alpm_strtoupper(key);
_alpm_strtrim(ptr);
if(!strcmp(key, "PKGNAME")) {
strncpy(info->name, ptr, sizeof(info->name));
} else if(!strcmp(key, "PKGVER")) {
strncpy(info->version, ptr, sizeof(info->version));
} else if(!strcmp(key, "PKGDESC")) {
strncpy(info->desc, ptr, sizeof(info->desc));
} else if(!strcmp(key, "GROUP")) {
info->groups = pm_list_add(info->groups, strdup(ptr));
} else if(!strcmp(key, "URL")) {
strncpy(info->url, ptr, sizeof(info->url));
} else if(!strcmp(key, "LICENSE")) {
strncpy(info->license, ptr, sizeof(info->license));
} else if(!strcmp(key, "BUILDDATE")) {
strncpy(info->builddate, ptr, sizeof(info->builddate));
} else if(!strcmp(key, "INSTALLDATE")) {
strncpy(info->installdate, ptr, sizeof(info->installdate));
} else if(!strcmp(key, "PACKAGER")) {
strncpy(info->packager, ptr, sizeof(info->packager));
} else if(!strcmp(key, "ARCH")) {
strncpy(info->arch, ptr, sizeof(info->arch));
} else if(!strcmp(key, "SIZE")) {
char tmp[32];
strncpy(tmp, ptr, sizeof(tmp));
info->size = atol(tmp);
} else if(!strcmp(key, "DEPEND")) {
info->depends = pm_list_add(info->depends, strdup(ptr));
} else if(!strcmp(key, "CONFLICT")) {
info->conflicts = pm_list_add(info->conflicts, strdup(ptr));
} else if(!strcmp(key, "REPLACES")) {
info->replaces = pm_list_add(info->replaces, strdup(ptr));
} else if(!strcmp(key, "PROVIDES")) {
info->provides = pm_list_add(info->provides, strdup(ptr));
} else if(!strcmp(key, "BACKUP")) {
info->backup = pm_list_add(info->backup, strdup(ptr));
} else {
fprintf(stderr, "%s: syntax error in description file line %d\n",
info->name[0] != '\0' ? info->name : "error", linenum);
}
}
line[0] = '\0';
}
fclose(fp);
unlink(descfile);
return(0);
}
pmpkg_t *pkg_load(char *pkgfile)
{
char *expath;
int i;
int config = 0;
int filelist = 0;
int scriptcheck = 0;
TAR *tar;
pmpkg_t *info = NULL;
tartype_t gztype = {
(openfunc_t)_alpm_gzopen_frontend,
(closefunc_t)gzclose,
(readfunc_t)gzread,
(writefunc_t)gzwrite
};
if(pkgfile == NULL) {
PM_RET_ERR(PM_ERR_WRONG_ARGS, NULL);
}
if(tar_open(&tar, pkgfile, &gztype, O_RDONLY, 0, TAR_GNU) == -1) {
PM_RET_ERR(PM_ERR_NOT_A_FILE, NULL);
}
info = pkg_new();
if(info == NULL) {
tar_close(tar);
PM_RET_ERR(PM_ERR_MEMORY, NULL);
}
for(i = 0; !th_read(tar); i++) {
if(config && filelist && scriptcheck) {
/* we have everything we need */
break;
}
if(!strcmp(th_get_pathname(tar), ".PKGINFO")) {
char *descfile;
/* extract this file into /tmp. it has info for us */
descfile = strdup("/tmp/pacman_XXXXXX");
mkstemp(descfile);
tar_extract_file(tar, descfile);
/* parse the info file */
if(parse_descfile(descfile, info, 0) == -1) {
goto error;
}
if(!strlen(info->name)) {
_alpm_log(PM_LOG_ERROR, "missing package name in %s", pkgfile);
goto error;
}
if(!strlen(info->version)) {
_alpm_log(PM_LOG_ERROR, "missing package version in %s", pkgfile);
goto error;
}
config = 1;
FREE(descfile);
continue;
} else if(!strcmp(th_get_pathname(tar), "._install") || !strcmp(th_get_pathname(tar), ".INSTALL")) {
info->scriptlet = 1;
scriptcheck = 1;
} else if(!strcmp(th_get_pathname(tar), ".FILELIST")) {
/* Build info->files from the filelist */
FILE *fp;
char *fn;
char *str;
MALLOC(str, PATH_MAX);
fn = strdup("/tmp/pacman_XXXXXX");
mkstemp(fn);
tar_extract_file(tar, fn);
fp = fopen(fn, "r");
while(!feof(fp)) {
if(fgets(str, PATH_MAX, fp) == NULL) {
continue;
}
_alpm_strtrim(str);
info->files = pm_list_add(info->files, strdup(str));
}
FREE(str);
fclose(fp);
if(unlink(fn)) {
_alpm_log(PM_LOG_WARNING, "could not remove tempfile %s\n", fn);
}
FREE(fn);
filelist = 1;
continue;
} else {
scriptcheck = 1;
if(!filelist) {
/* no .FILELIST present in this package.. build the filelist the */
/* old-fashioned way, one at a time */
expath = strdup(th_get_pathname(tar));
info->files = pm_list_add(info->files, expath);
}
}
if(TH_ISREG(tar) && tar_skip_regfile(tar)) {
_alpm_log(PM_LOG_ERROR, "bad package file in %s", pkgfile);
goto error;
}
expath = NULL;
}
tar_close(tar);
if(!config) {
_alpm_log(PM_LOG_ERROR, "missing package info file in %s", pkgfile);
goto error;
}
/* internal */
info->origin = PKG_FROM_FILE;
info->data = strdup(pkgfile);
info->infolevel = 0xFF;
return(info);
error:
printf("toto\n");
FREEPKG(info);
tar_close(tar);
return(NULL);
}
/* Helper function for sorting packages
*/
int pkg_cmp(const void *p1, const void *p2)
{
pmpkg_t *pkg1 = (pmpkg_t *)p1;
pmpkg_t *pkg2 = (pmpkg_t *)p2;
return(strcmp(pkg1->name, pkg2->name));
}
/* Test for existence of a package in a PMList*
* of pmpkg_t*
*
* returns: 0 for no match
* 1 for identical match
* -1 for name-only match (version mismatch)
*/
int pkg_isin(pmpkg_t *needle, PMList *haystack)
{
PMList *lp;
if(needle == NULL || haystack == NULL) {
return(0);
}
for(lp = haystack; lp; lp = lp->next) {
pmpkg_t *info = lp->data;
if(info && !strcmp(info->name, needle->name)) {
if(!strcmp(info->version, needle->version)) {
return(1);
}
return(-1);
}
}
return(0);
}
/* vim: set ts=2 sw=2 noet: */

78
lib/libalpm/package.h Normal file
View File

@ -0,0 +1,78 @@
/*
* package.h
*
* Copyright (c) 2002-2005 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 _ALPM_PACKAGE_H
#define _ALPM_PACKAGE_H
#include "list.h"
#define PKG_FROM_CACHE 1
#define PKG_FROM_FILE 2
typedef struct __pmpkg_t {
char name[256];
char version[64];
char desc[512];
char url[256];
char license[128];
char builddate[32];
char installdate[32];
char packager[64];
char md5sum[33];
char arch[32];
unsigned long size;
unsigned char scriptlet;
unsigned char force;
unsigned char reason;
PMList *replaces;
PMList *groups;
PMList *files;
PMList *backup;
PMList *depends;
PMList *requiredby;
PMList *conflicts;
PMList *provides;
/* internal */
unsigned char origin;
void *data;
unsigned char infolevel;
} pmpkg_t;
#define FREEPKG(p) do { if(p) { pkg_free(p); p = NULL; } } while(0)
#define FREELISTPKGS(p) do {\
if(p) { \
PMList *i;\
for(i = p; i; i = i->next) {\
FREEPKG(i->data); \
}\
FREELIST(p);\
} \
} while(0)
pmpkg_t* pkg_new();
void pkg_free(pmpkg_t *pkg);
pmpkg_t *pkg_load(char *pkgfile);
int pkg_cmp(const void *p1, const void *p2);
int pkg_isin(pmpkg_t *needle, PMList *haystack);
#endif /* _ALPM_PACKAGE_H */
/* vim: set ts=2 sw=2 noet: */

53
lib/libalpm/provide.c Normal file
View File

@ -0,0 +1,53 @@
/*
* provide.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdlib.h>
#include <string.h>
/* pacman */
#include "cache.h"
#include "list.h"
#include "db.h"
#include "alpm.h"
/* return a PMList of packages in "db" that provide "package"
*/
PMList *_alpm_db_whatprovides(pmdb_t *db, char *package)
{
PMList *pkgs = NULL;
PMList *lp;
if(db == NULL || package == NULL || strlen(package) == 0) {
return(NULL);
}
for(lp = db_get_pkgcache(db); lp; lp = lp->next) {
pmpkg_t *info = lp->data;
if(pm_list_is_strin(package, info->provides)) {
pkgs = pm_list_add(pkgs, info);
}
}
return(pkgs);
}
/* vim: set ts=2 sw=2 noet: */

33
lib/libalpm/provide.h Normal file
View File

@ -0,0 +1,33 @@
/*
* provide.h
*
* Copyright (c) 2002-2005 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 _ALPM_PROVIDE_H
#define _ALPM_PROVIDE_H
#include "config.h"
#include "list.h"
#include "db.h"
PMList *_alpm_db_whatprovides(pmdb_t *db, char *package);
#endif /* _ALPM_PROVIDE_H */
/* vim: set ts=2 sw=2 noet: */

259
lib/libalpm/remove.c Normal file
View File

@ -0,0 +1,259 @@
/*
* remove.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
#include <zlib.h>
#include <libtar.h>
/* pacman */
#include "util.h"
#include "error.h"
#include "rpmvercmp.h"
#include "md5.h"
#include "log.h"
#include "backup.h"
#include "package.h"
#include "db.h"
#include "cache.h"
#include "deps.h"
#include "provide.h"
#include "remove.h"
#include "handle.h"
#include "alpm.h"
extern pmhandle_t *handle;
int remove_loadtarget(pmdb_t *db, pmtrans_t *trans, char *name)
{
pmpkg_t *info;
ASSERT(db != NULL, PM_RET_ERR(PM_ERR_DB_NULL, -1));
ASSERT(trans != NULL, PM_RET_ERR(PM_ERR_TRANS_NULL, -1));
ASSERT(name != NULL, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
if((info = db_scan(db, name, INFRQ_ALL)) == NULL) {
_alpm_log(PM_LOG_ERROR, "could not find %s in database", name);
PM_RET_ERR(PM_ERR_PKG_NOT_FOUND, -1);
}
trans->packages = pm_list_add(trans->packages, info);
return(0);
}
int remove_prepare(pmdb_t *db, pmtrans_t *trans, PMList **data)
{
pmpkg_t *info;
PMList *lp;
ASSERT(db != NULL, PM_RET_ERR(PM_ERR_DB_NULL, -1));
ASSERT(trans != NULL, PM_RET_ERR(PM_ERR_TRANS_NULL, -1));
ASSERT(data != NULL, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
if(!(trans->flags & (PM_TRANS_FLAG_NODEPS)) && (trans->type != PM_TRANS_TYPE_UPGRADE)) {
TRANS_CB(trans, PM_TRANS_CB_DEPS_START, NULL, NULL);
if((lp = checkdeps(db, trans->type, trans->packages)) != NULL) {
if(trans->flags & PM_TRANS_FLAG_CASCADE) {
while(lp) {
PMList *j;
for(j = lp; j; j = j->next) {
pmdepmissing_t* miss = (pmdepmissing_t*)j->data;
info = db_scan(db, miss->depend.name, INFRQ_ALL);
if(!pkg_isin(info, trans->packages)) {
trans->packages = pm_list_add(trans->packages, info);
}
}
FREELIST(lp);
lp = checkdeps(db, trans->type, trans->packages);
}
} else {
*data = lp;
PM_RET_ERR(PM_ERR_UNSATISFIED_DEPS, -1);
}
}
if(trans->flags & PM_TRANS_FLAG_RECURSE) {
_alpm_log(PM_LOG_FLOW1, "finding removable dependencies...");
trans->packages = removedeps(db, trans->packages);
}
TRANS_CB(trans, PM_TRANS_CB_DEPS_DONE, NULL, NULL);
}
return(0);
}
int remove_commit(pmdb_t *db, pmtrans_t *trans)
{
pmpkg_t *info;
struct stat buf;
PMList *targ, *lp;
char line[PATH_MAX+1];
ASSERT(db != NULL, PM_RET_ERR(PM_ERR_DB_NULL, -1));
ASSERT(trans != NULL, PM_RET_ERR(PM_ERR_TRANS_NULL, -1));
for(targ = trans->packages; targ; targ = targ->next) {
char pm_install[PATH_MAX];
info = (pmpkg_t*)targ->data;
if(trans->type != PM_TRANS_TYPE_UPGRADE) {
TRANS_CB(trans, PM_TRANS_CB_REMOVE_START, info, NULL);
/* run the pre-remove scriptlet if it exists */
snprintf(pm_install, PATH_MAX, "%s%s/%s/%s-%s/install", handle->root, handle->dbpath, db->treename, info->name, info->version);
_alpm_runscriptlet(handle->root, pm_install, "pre_remove", info->version, NULL);
}
if(!(trans->flags & PM_TRANS_FLAG_DBONLY)) {
/* iterate through the list backwards, unlinking files */
for(lp = pm_list_last(info->files); lp; lp = lp->prev) {
char *newpath = NULL;
int nb = 0;
if(_alpm_needbackup(lp->data, info->backup)) {
nb = 1;
}
if(!nb && trans->type == PM_TRANS_TYPE_UPGRADE) {
/* check noupgrade */
if(pm_list_is_strin(lp->data, handle->noupgrade)) {
nb = 1;
}
}
snprintf(line, PATH_MAX, "%s%s", handle->root, (char*)lp->data);
if(lstat(line, &buf)) {
_alpm_log(PM_LOG_ERROR, "file %s does not exist", line);
continue;
}
if(S_ISDIR(buf.st_mode)) {
_alpm_log(PM_LOG_DEBUG, "removing directory %s", line);
if(rmdir(line)) {
/* this is okay, other packages are probably using it. */
}
} else {
/* if the file is flagged, back it up to .pacsave */
if(nb) {
if(trans->type == PM_TRANS_TYPE_UPGRADE) {
/* we're upgrading so just leave the file as is. pacman_add() will handle it */
} else {
if(!(trans->flags & PM_TRANS_FLAG_NOSAVE)) {
newpath = (char*)realloc(newpath, strlen(line)+strlen(".pacsave")+1);
sprintf(newpath, "%s.pacsave", line);
rename(line, newpath);
_alpm_log(PM_LOG_WARNING, "%s saved as %s", line, newpath);
alpm_logaction("%s saved as %s", line, newpath);
} else {
_alpm_log(PM_LOG_DEBUG, "unlinking %s", line);
if(unlink(line)) {
_alpm_log(PM_LOG_ERROR, "cannot remove file %s", line);
}
}
}
} else {
_alpm_log(PM_LOG_DEBUG, "unlinking %s", line);
if(unlink(line)) {
_alpm_log(PM_LOG_ERROR, "cannot remove file %s", line);
}
}
}
}
}
if(trans->type != PM_TRANS_TYPE_UPGRADE) {
char pm_install[PATH_MAX];
/* run the post-remove script if it exists */
snprintf(pm_install, PATH_MAX, "%s%s/%s/%s-%s/install", handle->root, handle->dbpath, db->treename, info->name, info->version);
_alpm_runscriptlet(handle->root, pm_install, "post_remove", info->version, NULL);
}
/* remove the package from the database */
if(db_remove(db, info) == -1) {
_alpm_log(PM_LOG_ERROR, "failed to remove database entry %s/%s-%s", db->path, info->name, info->version);
}
/* update dependency packages' REQUIREDBY fields */
for(lp = info->depends; lp; lp = lp->next) {
PMList *last, *j;
pmpkg_t *depinfo = NULL;
pmdepend_t depend;
splitdep((char*)lp->data, &depend);
depinfo = db_scan(db, depend.name, INFRQ_DESC|INFRQ_DEPENDS);
if(depinfo == NULL) {
/* look for a provides package */
PMList *provides = _alpm_db_whatprovides(db, depend.name);
if(provides) {
/* TODO: should check _all_ packages listed in provides, not just
* the first one.
*/
/* use the first one */
depinfo = db_scan(db, provides->data, INFRQ_DEPENDS);
FREELIST(provides);
if(depinfo == NULL) {
/* wtf */
continue;
}
} else {
continue;
}
}
/* splice out this entry from requiredby */
last = pm_list_last(depinfo->requiredby);
/* ORE - use list_remove here? */
for(j = depinfo->requiredby; j; j = j->next) {
if(!strcmp((char*)j->data, info->name)) {
if(j == depinfo->requiredby) {
depinfo->requiredby = j->next;
}
if(j->prev) j->prev->next = j->next;
if(j->next) j->next->prev = j->prev;
/* free the spliced node */
j->prev = j->next = NULL;
FREELIST(j);
break;
}
}
db_write(db, depinfo, INFRQ_DEPENDS);
FREEPKG(depinfo);
}
if(trans->type != PM_TRANS_TYPE_UPGRADE) {
TRANS_CB(trans, PM_TRANS_CB_REMOVE_DONE, info, NULL);
alpm_logaction("removed %s (%s)", info->name, info->version);
}
}
/* run ldconfig if it exists */
_alpm_log(PM_LOG_FLOW2, "running \"%ssbin/ldconfig -r %s\"", handle->root, handle->root);
_alpm_ldconfig(handle->root);
/* cache needs to be rebuilt */
db_free_pkgcache(db);
return(0);
}
/* vim: set ts=2 sw=2 noet: */

34
lib/libalpm/remove.h Normal file
View File

@ -0,0 +1,34 @@
/*
* remove.h
*
* Copyright (c) 2002-2005 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 _ALPM_REMOVE_H
#define _ALPM_REMOVE_H
#include "list.h"
#include "db.h"
#include "trans.h"
int remove_loadtarget(pmdb_t *db, pmtrans_t *trans, char *name);
int remove_prepare(pmdb_t *db, pmtrans_t *trans, PMList **data);
int remove_commit(pmdb_t *db, pmtrans_t *trans);
#endif /* _ALPM_REMOVE_H */
/* vim: set ts=2 sw=2 noet: */

237
lib/libalpm/rpmvercmp.c Normal file
View File

@ -0,0 +1,237 @@
/*
* rpmvercmp.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
/* pacman */
#include "rpmvercmp.h"
/* this function was taken from rpm 4.0.4 and rewritten */
int rpmvercmp(const char *a, const char *b)
{
char *str1, *str2;
char *one, *two;
char *rel1 = NULL, *rel2 = NULL;
char oldch1, oldch2;
int is1num, is2num;
int rc;
if(!strcmp(a,b)) {
return(0);
}
str1 = strdup(a);
str2 = strdup(b);
/* lose the release number */
for(one = str1; *one && *one != '-'; one++);
if(one) {
*one = '\0';
rel1 = ++one;
}
for(two = str2; *two && *two != '-'; two++);
if(two) {
*two = '\0';
rel2 = ++two;
}
one = str1;
two = str2;
while(*one || *two) {
while(*one && !isalnum(*one)) one++;
while(*two && !isalnum(*two)) two++;
str1 = one;
str2 = two;
/* find the next segment for each string */
if(isdigit(*str1)) {
is1num = 1;
while(*str1 && isdigit(*str1)) str1++;
} else {
is1num = 0;
while(*str1 && isalpha(*str1)) str1++;
}
if(isdigit(*str2)) {
is2num = 1;
while(*str2 && isdigit(*str2)) str2++;
} else {
is2num = 0;
while(*str2 && isalpha(*str2)) str2++;
}
oldch1 = *str1;
*str1 = '\0';
oldch2 = *str2;
*str2 = '\0';
/* see if we ran out of segments on one string */
if(one == str1 && two != str2) {
return(is2num ? -1 : 1);
}
if(one != str1 && two == str2) {
return(is1num ? 1 : -1);
}
/* see if we have a type mismatch (ie, one is alpha and one is digits) */
if(is1num && !is2num) return(1);
if(!is1num && is2num) return(-1);
if(is1num) while(*one == '0') one++;
if(is2num) while(*two == '0') two++;
rc = strverscmp(one, two);
if(rc) return(rc);
*str1 = oldch1;
*str2 = oldch2;
one = str1;
two = str2;
}
if((!*one) && (!*two)) {
/* compare release numbers */
if(rel1 && rel2) return(rpmvercmp(rel1, rel2));
return(0);
}
return(*one ? 1 : -1);
}
#ifndef HAVE_STRVERSCMP
/* GNU's strverscmp() function, taken from glibc 2.3.2 sources
*/
/* Compare strings while treating digits characters numerically.
Copyright (C) 1997, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jean-François Bignolles <bignolle@ecoledoc.ibp.fr>, 1997.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/* states: S_N: normal, S_I: comparing integral part, S_F: comparing
fractionnal parts, S_Z: idem but with leading Zeroes only */
#define S_N 0x0
#define S_I 0x4
#define S_F 0x8
#define S_Z 0xC
/* result_type: CMP: return diff; LEN: compare using len_diff/diff */
#define CMP 2
#define LEN 3
/* Compare S1 and S2 as strings holding indices/version numbers,
returning less than, equal to or greater than zero if S1 is less than,
equal to or greater than S2 (for more info, see the texinfo doc).
*/
int strverscmp (s1, s2)
const char *s1;
const char *s2;
{
const unsigned char *p1 = (const unsigned char *) s1;
const unsigned char *p2 = (const unsigned char *) s2;
unsigned char c1, c2;
int state;
int diff;
/* Symbol(s) 0 [1-9] others (padding)
Transition (10) 0 (01) d (00) x (11) - */
static const unsigned int next_state[] =
{
/* state x d 0 - */
/* S_N */ S_N, S_I, S_Z, S_N,
/* S_I */ S_N, S_I, S_I, S_I,
/* S_F */ S_N, S_F, S_F, S_F,
/* S_Z */ S_N, S_F, S_Z, S_Z
};
static const int result_type[] =
{
/* state x/x x/d x/0 x/- d/x d/d d/0 d/-
0/x 0/d 0/0 0/- -/x -/d -/0 -/- */
/* S_N */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
/* S_I */ CMP, -1, -1, CMP, +1, LEN, LEN, CMP,
+1, LEN, LEN, CMP, CMP, CMP, CMP, CMP,
/* S_F */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
/* S_Z */ CMP, +1, +1, CMP, -1, CMP, CMP, CMP,
-1, CMP, CMP, CMP
};
if (p1 == p2)
return 0;
c1 = *p1++;
c2 = *p2++;
/* Hint: '0' is a digit too. */
state = S_N | ((c1 == '0') + (isdigit (c1) != 0));
while ((diff = c1 - c2) == 0 && c1 != '\0')
{
state = next_state[state];
c1 = *p1++;
c2 = *p2++;
state |= (c1 == '0') + (isdigit (c1) != 0);
}
state = result_type[state << 2 | (((c2 == '0') + (isdigit (c2) != 0)))];
switch (state)
{
case CMP:
return diff;
case LEN:
while (isdigit (*p1++))
if (!isdigit (*p2++))
return 1;
return isdigit (*p2) ? -1 : diff;
default:
return state;
}
}
#endif
/* vim: set ts=2 sw=2 noet: */

32
lib/libalpm/rpmvercmp.h Normal file
View File

@ -0,0 +1,32 @@
/*
* rpmvercmp.h
*
* 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 _PM_RPMVERCMP_H
#define _PM_RPMVERCMP_H
int rpmvercmp(const char *a, const char *b);
#ifndef HAVE_STRVERSCMP
int strverscmp(const char *s1, const char *s2);
#endif
#endif
/* vim: set ts=2 sw=2 noet: */

248
lib/libalpm/sync.c Normal file
View File

@ -0,0 +1,248 @@
/*
* sync.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* pacman */
#include "log.h"
#include "util.h"
#include "list.h"
#include "package.h"
#include "db.h"
#include "cache.h"
#include "deps.h"
#include "trans.h"
#include "sync.h"
#include "rpmvercmp.h"
#include "handle.h"
extern pmhandle_t *handle;
pmsync_t *sync_new(int type, pmpkg_t *lpkg, pmpkg_t *spkg)
{
pmsync_t *sync;
if((sync = (pmsync_t *)malloc(sizeof(pmsync_t))) == NULL) {
return(NULL);
}
sync->type = type;
sync->lpkg = lpkg;
sync->spkg = spkg;
return(sync);
}
int sync_sysupgrade(PMList **data)
{
PMList *i, *j, *k;
PMList *targets = NULL;
*data = NULL;
/* check for "recommended" package replacements */
for(i = handle->dbs_sync; i; i = i->next) {
PMList *j;
for(j = db_get_pkgcache(i->data); j; j = j->next) {
pmpkg_t *spkg = j->data;
for(k = spkg->replaces; k; k = k->next) {
PMList *m;
for(m = db_get_pkgcache(handle->db_local); m; m = m->next) {
pmpkg_t *lpkg = m->data;
if(!strcmp(k->data, lpkg->name)) {
if(pm_list_is_strin(lpkg->name, handle->ignorepkg)) {
_alpm_log(PM_LOG_WARNING, "%s-%s: ignoring package upgrade (to be replaced by %s-%s)",
lpkg->name, lpkg->version, spkg->name, spkg->version);
} else {
pmsync_t *sync = sync_new(PM_SYSUPG_REPLACE, lpkg, spkg);
if(sync == NULL) {
pm_errno = PM_ERR_MEMORY;
goto error;
}
targets = pm_list_add(targets, sync);
}
}
}
}
}
}
/* match installed packages with the sync dbs and compare versions */
for(i = db_get_pkgcache(handle->db_local); i; i = i->next) {
int cmp;
pmpkg_t *local = i->data;
pmpkg_t *spkg = NULL;
pmsync_t *sync;
for(j = handle->dbs_sync; !spkg && j; j = j->next) {
for(k = db_get_pkgcache(j->data); !spkg && k; k = k->next) {
pmpkg_t *sp = k->data;
if(!strcmp(local->name, sp->name)) {
spkg = sp;
}
}
}
if(spkg == NULL) {
/*fprintf(stderr, "%s: not found in sync db. skipping.", local->name);*/
continue;
}
/* compare versions and see if we need to upgrade */
cmp = rpmvercmp(local->version, spkg->version);
if(cmp > 0 && !spkg->force) {
/* local version is newer */
_alpm_log(PM_LOG_FLOW1, "%s-%s: local version is newer",
local->name, local->version);
continue;
} else if(cmp == 0) {
/* versions are identical */
continue;
} else if(pm_list_is_strin(i->data, handle->ignorepkg)) {
/* package should be ignored (IgnorePkg) */
_alpm_log(PM_LOG_FLOW1, "%s-%s: ignoring package upgrade (%s)",
local->name, local->version, spkg->version);
continue;
}
sync = sync_new(PM_SYSUPG_UPGRADE, local, spkg);
if(sync == NULL) {
pm_errno = PM_ERR_MEMORY;
goto error;
}
targets = pm_list_add(targets, sync);
}
*data = targets;
return(0);
error:
FREELIST(targets);
return(-1);
}
int sync_resolvedeps(PMList **syncs)
{
return(0);
}
int sync_prepare(pmdb_t *db, pmtrans_t *trans, PMList **data)
{
PMList *i;
PMList *trail = NULL;
/* Resolve targets dependencies */
for(i = trans->targets; i; i = i->next) {
if(resolvedeps(handle->db_local, handle->dbs_sync, i->data, trans->targets, trail, data) == -1) {
/* pm_errno is set by resolvedeps */
goto error;
}
}
/* ORE
check for inter-conflicts and whatnot */
/* ORE
any packages in rmtargs need to be removed from final.
rather than ripping out nodes from final, we just copy over
our "good" nodes to a new list and reassign. */
/* ORE
Check dependencies of packages in rmtargs and make sure
we won't be breaking anything by removing them.
If a broken dep is detected, make sure it's not from a
package that's in our final (upgrade) list. */
return(0);
error:
return(-1);
}
int sync_commit(pmdb_t *db, pmtrans_t *trans)
{
PMList *i, *files = NULL;
PMList *final = NULL;
PMList *data;
pmtrans_t *tr;
/* remove any conflicting packages (WITHOUT dep checks) */
/* remove to-be-replaced packages */
/* install targets */
tr = trans_new(PM_TRANS_TYPE_UPGRADE, 0);
for(i = files; i; i = i->next) {
trans_addtarget(tr, i->data);
}
trans_prepare(tr, &data);
trans_commit(tr);
trans_free(tr);
/* propagate replaced packages' requiredby fields to their new owners */
for(i = final; i; i = i->next) {
/*syncpkg_t *sync = (syncpkg_t*)i->data;
if(sync->replaces) {
pkginfo_t *new = db_scan(db, sync->pkg->name, INFRQ_DEPENDS);
for(j = sync->replaces; j; j = j->next) {
pkginfo_t *old = (pkginfo_t*)j->data;
// merge lists
for(k = old->requiredby; k; k = k->next) {
if(!is_in(k->data, new->requiredby)) {
// replace old's name with new's name in the requiredby's dependency list
PMList *m;
pkginfo_t *depender = db_scan(db, k->data, INFRQ_DEPENDS);
for(m = depender->depends; m; m = m->next) {
if(!strcmp(m->data, old->name)) {
FREE(m->data);
m->data = strdup(new->name);
}
}
db_write(db, depender, INFRQ_DEPENDS);
// add the new requiredby
new->requiredby = list_add(new->requiredby, strdup(k->data));
}
}
}
db_write(db, new, INFRQ_DEPENDS);
FREEPKG(new);
}*/
}
return(0);
}
/* vim: set ts=2 sw=2 noet: */

47
lib/libalpm/sync.h Normal file
View File

@ -0,0 +1,47 @@
/*
* sync.h
*
* Copyright (c) 2002-2005 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 _ALPM_SYNC_H
#define _ALPM_SYNC_H
#include "db.h"
#include "package.h"
#include "trans.h"
#include "alpm.h"
typedef struct __pmsync_t {
unsigned char type;
pmpkg_t *lpkg;
pmpkg_t *spkg;
} pmsync_t;
pmsync_t *sync_new(int type, pmpkg_t *lpkg, pmpkg_t *spkg);
/*int sync_findpkg(char *name, PMList *dbs, pmsyncpkg_t **sync);
pmsyncpkg_t *find_pkginsync(char *needle, PMList *haystack);
PMList *rm_pkginsync(char *needle, PMList *haystack);*/
int sync_sysupgrade(PMList **data);
int sync_prepare(pmdb_t *db, pmtrans_t *trans, PMList **data);
int sync_commit(pmdb_t *db, pmtrans_t *trans);
#endif /* _ALPM_SYNC_H */
/* vim: set ts=2 sw=2 noet: */

187
lib/libalpm/trans.c Normal file
View File

@ -0,0 +1,187 @@
/*
* trans.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* pacman */
#include "error.h"
#include "package.h"
#include "util.h"
#include "list.h"
#include "handle.h"
#include "add.h"
#include "remove.h"
#include "sync.h"
#include "alpm.h"
extern pmhandle_t *handle;
pmtrans_t *trans_new()
{
pmtrans_t *trans;
if((trans = (pmtrans_t *)malloc(sizeof(pmtrans_t))) == NULL) {
return(NULL);
}
trans->targets = NULL;
trans->packages = NULL;
trans->type = 0;
trans->flags = 0;
trans->cb = NULL;
trans->state = STATE_IDLE;
return(trans);
}
void trans_free(pmtrans_t *trans)
{
if(trans == NULL) {
return;
}
FREELIST(trans->targets);
FREELISTPKGS(trans->packages);
free(trans);
}
int trans_init(pmtrans_t *trans, unsigned char type, unsigned char flags, alpm_trans_cb cb)
{
/* Sanity checks */
if(trans == NULL) {
PM_RET_ERR(PM_ERR_TRANS_NULL, -1);
}
/* ORE
perform sanity checks on type and flags:
for instance, we can't set UPGRADE and FRESHEN at the same time */
trans->type = type;
trans->flags = flags;
trans->cb = cb;
trans->state = STATE_INITIALIZED;
return(0);
}
int trans_addtarget(pmtrans_t *trans, char *target)
{
/* Sanity checks */
ASSERT(trans != NULL, PM_RET_ERR(PM_ERR_TRANS_NULL, -1));
ASSERT(target != NULL, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
if(pm_list_is_strin(target, trans->targets)) {
PM_RET_ERR(PM_ERR_TRANS_DUP_TARGET, -1);
}
switch(trans->type) {
case PM_TRANS_TYPE_ADD:
case PM_TRANS_TYPE_UPGRADE:
if(add_loadtarget(handle->db_local, trans, target) == -1) {
/* pm_errno is set by add_loadtarget() */
return(-1);
}
break;
case PM_TRANS_TYPE_REMOVE:
if(remove_loadtarget(handle->db_local, trans, target) == -1) {
/* pm_errno is set by remove_loadtarget() */
return(-1);
}
break;
}
trans->targets = pm_list_add(trans->targets, strdup(target));
trans->state = STATE_INITIALIZED;
return(0);
}
int trans_prepare(pmtrans_t *trans, PMList **data)
{
*data = NULL;
/* Sanity checks */
ASSERT(trans != NULL, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
ASSERT(trans->packages != NULL, return(0));
switch(trans->type) {
case PM_TRANS_TYPE_ADD:
case PM_TRANS_TYPE_UPGRADE:
if(add_prepare(handle->db_local, trans, data) == -1) {
/* pm_errno is set by add_prepare() */
return(-1);
}
break;
case PM_TRANS_TYPE_REMOVE:
if(remove_prepare(handle->db_local, trans, data) == -1) {
/* pm_errno is set by remove_prepare() */
return(-1);
}
break;
case PM_TRANS_TYPE_SYNC:
if(sync_prepare(handle->db_local, trans, data) == -1) {
/* pm_errno is set by sync_prepare() */
return(-1);
}
break;
}
trans->state = STATE_PREPARED;
return(0);
}
int trans_commit(pmtrans_t *trans)
{
/* Sanity checks */
ASSERT(trans != NULL, PM_RET_ERR(PM_ERR_WRONG_ARGS, -1));
/* If there's nothing to do, return without complaining */
ASSERT(trans->packages != NULL, return(0));
switch(trans->type) {
case PM_TRANS_TYPE_ADD:
case PM_TRANS_TYPE_UPGRADE:
if(add_commit(handle->db_local, trans) == -1) {
return(-1);
}
break;
case PM_TRANS_TYPE_REMOVE:
if(remove_commit(handle->db_local, trans) == -1) {
return(-1);
}
break;
case PM_TRANS_TYPE_SYNC:
if(sync_commit(handle->db_local, trans) == -1) {
return(-1);
}
break;
}
trans->state = STATE_COMMITED;
return(0);
}
/* vim: set ts=2 sw=2 noet: */

54
lib/libalpm/trans.h Normal file
View File

@ -0,0 +1,54 @@
/*
* trans.h
*
* Copyright (c) 2002-2005 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 _ALPM_TRANS_H
#define _ALPM_TRANS_H
enum {
STATE_IDLE = 0,
STATE_INITIALIZED,
STATE_PREPARED,
STATE_COMMITED
};
#include "alpm.h"
typedef struct __pmtrans_t {
unsigned char type;
unsigned char flags;
unsigned char state;
PMList *targets; /* PMList of (char *) */
PMList *packages; /* PMList of (pmpkginfo_t *) */
alpm_trans_cb cb;
} pmtrans_t;
#define FREETRANS(p) do { if (p) { trans_free(p); p = NULL; } } while (0)
#define TRANS_CB(t, e, d1, d2) do { if((t) && (t)->cb) { (t)->cb(e, d1, d2); } } while(0)
pmtrans_t *trans_new();
void trans_free(pmtrans_t *trans);
int trans_init(pmtrans_t *trans, unsigned char type, unsigned char flags, alpm_trans_cb cb);
int trans_addtarget(pmtrans_t *trans, char *target);
int trans_prepare(pmtrans_t *trans, PMList **data);
int trans_commit(pmtrans_t *trans);
#endif /* _ALPM_TRANS_H */
/* vim: set ts=2 sw=2 noet: */

401
lib/libalpm/util.c Normal file
View File

@ -0,0 +1,401 @@
/*
* util.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <dirent.h>
#include <time.h>
#include <syslog.h>
#include <zlib.h>
#include <libtar.h>
/* pacman */
#include "log.h"
#include "util.h"
#include "alpm.h"
/* borrowed and modified from Per Liden's pkgutils (http://crux.nu) */
long _alpm_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 (long)gzf;
}
/* does the same thing as 'mkdir -p' */
int _alpm_makepath(char *path)
{
char *orig, *str, *ptr;
char full[PATH_MAX] = "";
mode_t oldmask;
oldmask = umask(0000);
orig = strdup(path);
str = orig;
while((ptr = strsep(&str, "/"))) {
if(strlen(ptr)) {
struct stat buf;
strcat(full, "/");
strcat(full, ptr);
if(stat(full, &buf)) {
if(mkdir(full, 0755)) {
free(orig);
umask(oldmask);
return(1);
}
}
}
}
free(orig);
umask(oldmask);
return(0);
}
int _alpm_copyfile(char *src, char *dest)
{
FILE *in, *out;
size_t len;
char buf[4097];
in = fopen(src, "r");
if(in == NULL) {
return(1);
}
out = fopen(dest, "w");
if(out == NULL) {
return(1);
}
while((len = fread(buf, 1, 4096, in))) {
fwrite(buf, 1, len, out);
}
fclose(in);
fclose(out);
return(0);
}
/* Convert a string to uppercase
*/
char *_alpm_strtoupper(char *str)
{
char *ptr = str;
while(*ptr) {
(*ptr) = toupper(*ptr);
ptr++;
}
return str;
}
/* Trim whitespace and newlines from a string
*/
char *_alpm_strtrim(char *str)
{
char *pch = str;
while(isspace(*pch)) {
pch++;
}
if(pch != str) {
memmove(str, pch, (strlen(pch) + 1));
}
pch = (char*)(str + (strlen(str) - 1));
while(isspace(*pch)) {
pch--;
}
*++pch = '\0';
return str;
}
/* A cheap grep for text files, returns 1 if a substring
* was found in the text file fn, 0 if it wasn't
*/
int _alpm_grep(const char *fn, const char *needle)
{
FILE *fp;
if((fp = fopen(fn, "r")) == NULL) {
return(0);
}
while(!feof(fp)) {
char line[1024];
fgets(line, 1024, fp);
if(feof(fp)) {
continue;
}
if(strstr(line, needle)) {
fclose(fp);
return(1);
}
}
fclose(fp);
return(0);
}
/* Create a lock file
*/
int _alpm_lckmk(char *file)
{
int fd, count = 0;
while((fd = open(file, O_WRONLY | O_CREAT | O_EXCL, 0000)) == -1 && errno == EACCES) {
if(++count < 1) {
sleep(1);
} else {
return(-1);
}
}
return(fd > 0 ? 0 : -1);
return(0);
}
/* Remove a lock file
*/
int _alpm_lckrm(char *file)
{
return(unlink(file) == -1);
}
int _alpm_unpack(char *archive, const char *prefix, const char *fn)
{
TAR *tar = NULL;
char expath[PATH_MAX];
tartype_t gztype = {
(openfunc_t) _alpm_gzopen_frontend,
(closefunc_t)gzclose,
(readfunc_t) gzread,
(writefunc_t)gzwrite
};
/* open the .tar.gz package */
if(tar_open(&tar, archive, &gztype, O_RDONLY, 0, TAR_GNU) == -1) {
perror(archive);
return(1);
}
while(!th_read(tar)) {
if(fn && strcmp(fn, th_get_pathname(tar))) {
if(TH_ISREG(tar) && tar_skip_regfile(tar)) {
char errorstr[255];
snprintf(errorstr, 255, "bad tar archive: %s", archive);
perror(errorstr);
tar_close(tar);
return(1);
}
continue;
}
snprintf(expath, PATH_MAX, "%s/%s", prefix, th_get_pathname(tar));
if(tar_extract_file(tar, expath)) {
fprintf(stderr, "could not extract %s: %s\n", th_get_pathname(tar), strerror(errno));
}
if(fn) break;
}
tar_close(tar);
return(0);
}
/* does the same thing as 'rm -rf' */
int _alpm_rmrf(char *path)
{
int errflag = 0;
struct dirent *dp;
DIR *dirp;
char name[PATH_MAX];
extern int errno;
if(!unlink(path)) {
return(0);
} else {
if(errno == ENOENT) {
return(0);
} else if(errno == EPERM) {
/* fallthrough */
} else if(errno == EISDIR) {
/* fallthrough */
} else if(errno == ENOTDIR) {
return(1);
} else {
/* not a directory */
return(1);
}
if((dirp = opendir(path)) == (DIR *)-1) {
return(1);
}
for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
if(dp->d_ino) {
sprintf(name, "%s/%s", path, dp->d_name);
if(strcmp(dp->d_name, "..") && strcmp(dp->d_name, ".")) {
errflag += _alpm_rmrf(name);
}
}
}
closedir(dirp);
if(rmdir(path)) {
errflag++;
}
return(errflag);
}
return(0);
}
int _alpm_log_action(unsigned char usesyslog, FILE *f, char *fmt, ...)
{
char msg[1024];
va_list args;
va_start(args, fmt);
vsnprintf(msg, 1024, fmt, args);
va_end(args);
if(usesyslog) {
syslog(LOG_WARNING, "%s", msg);
}
if(f) {
time_t t;
struct tm *tm;
t = time(NULL);
tm = localtime(&t);
fprintf(f, "[%02d/%02d/%02d %02d:%02d] %s\n", tm->tm_mon+1, tm->tm_mday,
tm->tm_year-100, tm->tm_hour, tm->tm_min, msg);
}
return(0);
}
int _alpm_ldconfig(char *root)
{
char line[PATH_MAX];
struct stat buf;
snprintf(line, PATH_MAX, "%setc/ld.so.conf", root);
if(!stat(line, &buf)) {
snprintf(line, PATH_MAX, "%ssbin/ldconfig", root);
if(!stat(line, &buf)) {
char cmd[PATH_MAX];
snprintf(cmd, PATH_MAX, "%s -r %s", line, root);
system(cmd);
}
}
return(0);
}
int _alpm_runscriptlet(char *root, char *installfn, char *script, char *ver, char *oldver)
{
char scriptfn[PATH_MAX];
char cmdline[PATH_MAX];
char tmpdir[PATH_MAX] = "";
char *scriptpath;
struct stat buf;
return(0);
if(stat(installfn, &buf)) {
/* not found */
return(0);
}
if(!strcmp(script, "pre_upgrade") || !strcmp(script, "pre_install")) {
snprintf(tmpdir, PATH_MAX, "%stmp/", root);
if(stat(tmpdir, &buf)) {
_alpm_makepath(tmpdir);
}
snprintf(tmpdir, PATH_MAX, "%stmp/pacman-XXXXXX", root);
if(mkdtemp(tmpdir) == NULL) {
perror("error creating temp directory");
return(1);
}
_alpm_unpack(installfn, tmpdir, ".INSTALL");
snprintf(scriptfn, PATH_MAX, "%s/.INSTALL", tmpdir);
/* chop off the root so we can find the tmpdir in the chroot */
scriptpath = scriptfn + strlen(root) - 1;
return(0);
} else {
strncpy(scriptfn, installfn, PATH_MAX-1);
/* chop off the root so we can find the tmpdir in the chroot */
scriptpath = scriptfn + strlen(root) - 1;
}
if(!_alpm_grep(scriptfn, script)) {
/* script not found in scriptlet file */
return(0);
}
/* ORE
pm_cblog(PM_LOG_FLOW2, "Executing %s script...\n", script);*/
if(oldver) {
snprintf(cmdline, PATH_MAX, "echo \"umask 0022; source %s %s %s %s\" | chroot %s /bin/sh",
scriptpath, script, ver, oldver, root);
} else {
snprintf(cmdline, PATH_MAX, "echo \"umask 0022; source %s %s %s\" | chroot %s /bin/sh",
scriptpath, script, ver, root);
}
/* ORE
pm_cblog(PM_LOG_FLOW2, "%s\n", cmdline);*/
system(cmdline);
if(strlen(tmpdir) && _alpm_rmrf(tmpdir)) {
fprintf(stderr, "warning: could not remove tmpdir %s\n", tmpdir);
}
return(0);
}
/* vim: set ts=2 sw=2 noet: */

57
lib/libalpm/util.h Normal file
View File

@ -0,0 +1,57 @@
/*
* util.h
*
* Copyright (c) 2002-2005 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 _ALPM_UTIL_H
#define _ALPM_UTIL_H
#include <stdio.h>
#define MALLOC(p, b) { \
if((b) > 0) { \
p = malloc(b); \
if (!(p)) { \
fprintf(stderr, "malloc failure: could not allocate %d bytes\n", (b)); \
exit(1); \
} \
} else { \
p = NULL; \
} \
}
#define FREE(p) do { if (p) { free(p); p = NULL; } } while(0)
#define ASSERT(cond, action) do { if(!(cond)) { action; } } while(0)
long _alpm_gzopen_frontend(char *pathname, int oflags, int mode);
int _alpm_makepath(char *path);
int _alpm_copyfile(char *src, char *dest);
char *_alpm_strtoupper(char *str);
char *_alpm_strtrim(char *str);
int _alpm_grep(const char *fn, const char *needle);
int _alpm_lckmk(char *file);
int _alpm_lckrm(char *file);
int _alpm_unpack(char *archive, const char *prefix, const char *fn);
int _alpm_rmrf(char *path);
int _alpm_log_action(unsigned char usesyslog, FILE *f, char *fmt, ...);
int _alpm_ldconfig(char *root);
int _alpm_runscriptlet(char *util, char *installfn, char *script, char *ver, char *oldver);
#endif /* _ALPM_UTIL_H */
/* vim: set ts=2 sw=2 noet: */

68
lib/libftp/Makefile Normal file
View File

@ -0,0 +1,68 @@
#
# This makefile contains modifications submitted by Richard Braakman
# (dark@xs4all.nl) for the shared library generation.
#
# By default, ftplib uses PASV. If you need it to use PORT
# instead, uncomment the next line
DEFINES = -DFTPLIB_DEFMODE=FTPLIB_PORT
SONAME = 3
SOVERSION = $(SONAME).1
TARGETS = qftp libftp.a libftp.so
OBJECTS = qftp.o ftplib.o
SOURCES = qftp.c ftplib.c
CFLAGS = -Wall $(DEBUG) -I. $(INCLUDES) $(DEFINES)
LDFLAGS = -L.
DEPFLAGS =
all : $(TARGETS)
clean :
rm -f $(OBJECTS) core *.bak
rm -rf unshared
clobber : clean
rm -f $(TARGETS) .depend
rm -f libftp.so.*
install : all
install qftp /usr/local/bin
install -m 644 libftp.so.$(SOVERSION) /usr/local/lib
install -m 644 ftplib.h /usr/local/include
(cd /usr/local/lib && \
ln -sf libftp.so.$(SOVERSION) libftp.so.$(SONAME) && \
ln -sf libftp.so.$(SONAME) libftp.so)
-(cd /usr/local/bin && \
for f in ftpdir ftpget ftplist ftprm ftpsend; \
do ln -s qftp $$f; done)
depend :
$(CC) $(CFLAGS) -M $(SOURCES) > .depend
# build without -fPIC
unshared/ftplib.o: ftplib.c ftplib.h
-mkdir unshared
$(CC) -c $(CFLAGS) -D_REENTRANT $< -o $@
ftplib.o: ftplib.c ftplib.h
$(CC) -c $(CFLAGS) -fPIC -D_REENTRANT $< -o $@
libftp.a: unshared/ftplib.o
ar -rcs $@ $<
libftp.so.$(SOVERSION): ftplib.o
$(CC) -shared -Wl,-soname,libftp.so.$(SONAME) -lc -o $@ $<
libftp.so: libftp.so.$(SOVERSION)
ln -sf $< libftp.so.$(SONAME)
ln -sf $< $@
qftp : qftp.o libftp.so ftplib.h
$(CC) $(LDFLAGS) -o $@ $< -lftp
ifeq (.depend,$(wildcard .depend))
include .depend
endif

1569
lib/libftp/ftplib.c Normal file

File diff suppressed because it is too large Load Diff

131
lib/libftp/ftplib.h Normal file
View File

@ -0,0 +1,131 @@
/***************************************************************************/
/* */
/* ftplib.h - header file for callable ftp access routines */
/* Copyright (C) 1996, 1997 Thomas Pfau, pfau@cnj.digex.net */
/* 73 Catherine Street, South Bound Brook, NJ, 08880 */
/* */
/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Library General Public */
/* License as published by the Free Software Foundation; either */
/* version 2 of the License, or (at your option) any later version. */
/* */
/* This library 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 */
/* Library General Public License for more details. */
/* */
/* You should have received a copy of the GNU Library General Public */
/* License along with this progam; if not, write to the */
/* Free Software Foundation, Inc., 59 Temple Place - Suite 330, */
/* Boston, MA 02111-1307, USA. */
/* */
/***************************************************************************/
#if !defined(__FTPLIB_H)
#define __FTPLIB_H
#if defined(__unix__) || defined(VMS)
#define GLOBALDEF
#define GLOBALREF extern
#elif defined(_WIN32)
#if defined BUILDING_LIBRARY
#define GLOBALDEF __declspec(dllexport)
#define GLOBALREF __declspec(dllexport)
#else
#define GLOBALREF __declspec(dllimport)
#endif
#endif
/* FtpAccess() type codes */
#define FTPLIB_DIR 1
#define FTPLIB_DIR_VERBOSE 2
#define FTPLIB_FILE_READ 3
#define FTPLIB_FILE_WRITE 4
/* FtpAccess() mode codes */
#define FTPLIB_ASCII 'A'
#define FTPLIB_IMAGE 'I'
#define FTPLIB_TEXT FTPLIB_ASCII
#define FTPLIB_BINARY FTPLIB_IMAGE
/* connection modes */
#define FTPLIB_PASSIVE 1
#define FTPLIB_PORT 2
/* connection option names */
#define FTPLIB_CONNMODE 1
#define FTPLIB_CALLBACK 2
#define FTPLIB_IDLETIME 3
#define FTPLIB_CALLBACKARG 4
#define FTPLIB_CALLBACKBYTES 5
#ifdef __cplusplus
extern "C" {
#endif
typedef struct NetBuf netbuf;
typedef int (*FtpCallback)(netbuf *nControl, int xfered, void *arg);
/* v1 compatibility stuff */
#if !defined(_FTPLIB_NO_COMPAT)
netbuf *DefaultNetbuf;
#define ftplib_lastresp FtpLastResponse(DefaultNetbuf)
#define ftpInit FtpInit
#define ftpOpen(x) FtpConnect(x, &DefaultNetbuf)
#define ftpLogin(x,y) FtpLogin(x, y, DefaultNetbuf)
#define ftpSite(x) FtpSite(x, DefaultNetbuf)
#define ftpMkdir(x) FtpMkdir(x, DefaultNetbuf)
#define ftpChdir(x) FtpChdir(x, DefaultNetbuf)
#define ftpRmdir(x) FtpRmdir(x, DefaultNetbuf)
#define ftpNlst(x, y) FtpNlst(x, y, DefaultNetbuf)
#define ftpDir(x, y) FtpDir(x, y, DefaultNetbuf)
#define ftpGet(x, y, z) FtpGet(x, y, z, DefaultNetbuf)
#define ftpPut(x, y, z) FtpPut(x, y, z, DefaultNetbuf)
#define ftpRename(x, y) FtpRename(x, y, DefaultNetbuf)
#define ftpDelete(x) FtpDelete(x, DefaultNetbuf)
#define ftpQuit() FtpQuit(DefaultNetbuf)
#endif /* (_FTPLIB_NO_COMPAT) */
/* end v1 compatibility stuff */
GLOBALREF int ftplib_debug;
GLOBALREF void FtpInit(void);
GLOBALREF char *FtpLastResponse(netbuf *nControl);
GLOBALREF int FtpConnect(const char *host, netbuf **nControl);
GLOBALREF int FtpOptions(int opt, long val, netbuf *nControl);
GLOBALREF int FtpLogin(const char *user, const char *pass, netbuf *nControl);
GLOBALREF int FtpAccess(const char *path, int typ, int mode, netbuf *nControl,
netbuf **nData);
GLOBALREF int FtpRead(void *buf, int max, netbuf *nData);
GLOBALREF int FtpWrite(void *buf, int len, netbuf *nData);
GLOBALREF int FtpClose(netbuf *nData);
GLOBALREF int FtpSite(const char *cmd, netbuf *nControl);
GLOBALREF int FtpSysType(char *buf, int max, netbuf *nControl);
GLOBALREF int FtpMkdir(const char *path, netbuf *nControl);
GLOBALREF int FtpChdir(const char *path, netbuf *nControl);
GLOBALREF int FtpCDUp(netbuf *nControl);
GLOBALREF int FtpRmdir(const char *path, netbuf *nControl);
GLOBALREF int FtpPwd(char *path, int max, netbuf *nControl);
GLOBALREF int FtpNlst(const char *output, const char *path, netbuf *nControl);
GLOBALREF int FtpDir(const char *output, const char *path, netbuf *nControl);
GLOBALREF int FtpSize(const char *path, int *size, char mode, netbuf *nControl);
GLOBALREF int FtpRestart(int offset, netbuf *nControl);
GLOBALREF int FtpModDate(const char *path, char *dt, int max, netbuf *nControl);
GLOBALREF int FtpGet(const char *output, const char *path, char mode,
netbuf *nControl);
GLOBALREF int FtpPut(const char *input, const char *path, char mode,
netbuf *nControl);
GLOBALREF int FtpRename(const char *src, const char *dst, netbuf *nControl);
GLOBALREF int FtpDelete(const char *fnm, netbuf *nControl);
GLOBALREF void FtpQuit(netbuf *nControl);
GLOBALREF int HttpConnect(const char *host, unsigned short port, netbuf **nControl);
GLOBALREF int HttpGet(const char *host, const char *output, const char *path,
int *size, netbuf *nControl, unsigned int offset);
GLOBALREF void HttpQuit(netbuf *nControl);
#ifdef __cplusplus
};
#endif
#endif /* __FTPLIB_H */

186
scripts/gensync Executable file
View File

@ -0,0 +1,186 @@
#!/bin/bash
#
# gensync
#
# Copyright (c) 2002-2004 by Judd Vinet <jvinet@zeroflux.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
# USA.
#
myver='2.9.2'
usage() {
echo "gensync $myver"
echo "usage: $0 <root> <destfile> [package_directory]"
echo
echo "gensync will generate a sync database by reading all PKGBUILD files"
echo "from <root>. gensync builds the database in a temporary directory"
echo "and then compresses it to <destfile>."
echo
echo "gensync will calculate md5sums of packages in the same directory as"
echo "<destfile>, unless an alternate [package_directory] is specified."
echo
echo "note: The <destfile> name is important. It must be of the form"
echo " {treename}.db.tar.gz where {treename} is the name of the custom"
echo " package repository you configured in /etc/pacman.conf. The"
echo " generated database must reside in the same directory as your"
echo " custom packages (also configured in /etc/pacman.conf)"
echo
echo "example: gensync /var/abs/local /home/mypkgs/custom.db.tar.gz"
echo
echo
exit 0
}
die() {
echo "gensync: $*" >&2
rm -rf $gstmpdir
exit 1
}
get_md5checksum()
{
if [ "$pkgdir" != "" ]; then
pkgfile="$pkgdir/$pkgname-$pkgver-$pkgrel.pkg.tar.gz"
else
pkgfile="$destdir/$pkgname-$pkgver-$pkgrel.pkg.tar.gz"
fi
if [ -f $pkgfile ]; then
md5line=`md5sum $pkgfile`
[ ! -z "$md5line" ] && pkgmd5sum=${md5line% *}
echo $pkgmd5sum
fi
return 0
}
db_write_entry()
{
unset pkgname pkgver pkgrel pkgdesc force
unset groups replaces provides depends conflicts
source $1 || return 1
cd $gstmpdir
mkdir $pkgname-$pkgver-$pkgrel || return 1
cd $pkgname-$pkgver-$pkgrel
# desc
: >desc
echo "%NAME%" >>desc
echo "$pkgname" >>desc
echo "" >>desc
echo "%VERSION%" >>desc
echo "$pkgver-$pkgrel" >>desc
echo "" >>desc
echo "%DESC%" >>desc
echo "$pkgdesc" >>desc
echo "" >>desc
echo "%CSIZE%" >>desc
echo "$csize" >>desc
echo "" >>desc
if [ ! -z $pkgmd5sum ]; then
echo "%MD5SUM%" >>desc
echo "$pkgmd5sum" >>desc
echo "" >>desc
fi
if [ ${#groups[*]} -gt 0 ]; then
echo "%GROUPS%" >>desc
for it in "${groups[@]}"; do
echo "$it" >>desc
done
echo "" >>desc
fi
if [ ${#replaces[*]} -gt 0 ]; then
echo "%REPLACES%" >>desc
for it in "${replaces[@]}"; do
echo "$it" >>desc
done
echo "" >>desc
fi
if [ "$force" = "y" -o "$force" = "Y" ]; then
echo "%FORCE%" >>desc
echo "" >>desc
fi
# depends
: >depends
if [ ${#depends[*]} -gt 0 ]; then
echo "%DEPENDS%" >>depends
for it in "${depends[@]}"; do
echo "$it" >>depends
done
echo "" >>depends
fi
if [ ${#conflicts[*]} -gt 0 ]; then
echo "%CONFLICTS%" >>depends
for it in "${conflicts[@]}"; do
echo "$it" >>depends
done
echo "" >>depends
fi
if [ ${#provides[*]} -gt 0 ]; then
echo "%PROVIDES%" >>depends
for it in "${provides[@]}"; do
echo "$it" >>depends
done
echo "" >>depends
fi
# preserve the modification time
touch -r $1 desc depends
}
if [ $# -lt 2 ]; then
usage
exit 0
fi
if [ "$1" = "-h" -o "$1" = "--help" ]; then
usage
exit 0
fi
d=`dirname $1`
rootdir=`cd $d && pwd`/`basename $1`
d=`dirname $2`
destdir=`cd $d && pwd`
destfile="$destdir/`basename $2`"
pkgdir=
if [ "$3" != "" ]; then
pkgdir=$3
fi
gstmpdir=$(mktemp -d /tmp/gensync.XXXXXXXXXX) || exit 1
[ ! -d $rootdir ] && die "invalid root dir: $rootdir"
echo "gensync: building database entries, generating md5sums..." >&2
cd `dirname $2`
for file in `find $rootdir/* -name PKGBUILD`; do
source $file || die "errors parsing $file"
if [ "$pkgdir" != "" ]; then
pkgfile="$pkgdir/$pkgname-$pkgver-$pkgrel.pkg.tar.gz"
else
pkgfile="$destdir/$pkgname-$pkgver-$pkgrel.pkg.tar.gz"
fi
[ -f $pkgfile ] || die "missing package file: $pkgfile"
csize=`du -b $pkgfile | cut -f1`
pkgmd5sum=`get_md5checksum $pkgfile`
[ -z $pkgmd5sum ] && die "error generating checksum for $pkgfile"
db_write_entry $file
[ $? -gt 0 ] && die "error writing entry for $file"
done
echo "gensync: compressing to $destfile..." >&2
cd $gstmpdir
tar c * | gzip -9 >$destfile
[ $? -gt 0 ] && die "error writing to $destfile"
rm -rf $gstmpdir
exit 0

701
scripts/makepkg Executable file
View File

@ -0,0 +1,701 @@
#!/bin/bash
#
# makepkg
#
# Copyright (c) 2002-2004 by Judd Vinet <jvinet@zeroflux.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
# USA.
#
myver='2.9.2'
startdir=`pwd`
PKGDEST=$startdir
USE_COLOR="n"
# source Arch's abs.conf if it's present
[ -f /etc/abs/abs.conf ] && source /etc/abs/abs.conf
# makepkg configuration
[ -f /etc/makepkg.conf ] && source /etc/makepkg.conf
INFAKEROOT=
if [ "$1" = "-F" ]; then
INFAKEROOT=1
shift
fi
### SUBROUTINES ###
plain() {
if [ "$USE_COLOR" = "Y" -o "$USE_COLOR" = "y" ]; then
echo -e " \033[1;1m$1\033[1;0m" >&2
else
echo " $1" >&2
fi
}
msg() {
if [ "$USE_COLOR" = "Y" -o "$USE_COLOR" = "y" ]; then
echo -e "\033[1;32m==>\033[1;0m \033[1;1m$1\033[1;0m" >&2
else
echo "==> $1" >&2
fi
}
warning() {
if [ "$USE_COLOR" = "Y" -o "$USE_COLOR" = "y" ]; then
echo -e "\033[1;33m==> WARNING:\033[1;0m \033[1;1m$1\033[1;0m" >&2
else
echo "==> WARNING: $1" >&2
fi
}
error() {
if [ "$USE_COLOR" = "Y" -o "$USE_COLOR" = "y" ]; then
echo -e "\033[1;31m==> ERROR:\033[1;0m \033[1;1m$1\033[1;0m" >&2
else
echo "==> ERROR: $1" >&2
fi
}
strip_url() {
echo $1 | sed 's|^.*://.*/||g'
}
checkdeps() {
local missdep=""
local deplist=""
missdep=`pacman -T $*`
ret=$?
if [ "$ret" != "0" ]; then
if [ "$ret" = "127" ]; then
msg "Missing Dependencies:"
msg ""
nl=0
for dep in $missdep; do
echo -ne "$dep " >&2
if [ "$nl" = "1" ]; then
nl=0
echo -ne "\n" >&2
# add this dep to the list
depname=`echo $dep | sed 's|=.*$||' | sed 's|>.*$||' | sed 's|<.*$||'`
deplist="$deplist $depname"
continue
fi
nl=1
done
msg ""
else
error "pacman returned a fatal error."
exit 1
fi
fi
echo $deplist
}
handledeps() {
local missingdeps=0
local deplist="$*"
local haveperm=0
if [ "`id -u`" = "0" -a "$INFAKEROOT" != "1" ]; then
haveperm=1
fi
if [ "$deplist" != "" -a $haveperm -eq 1 ]; then
if [ "$DEP_BIN" = "1" ]; then
# install missing deps from binary packages (using pacman -S)
msg "Installing missing dependencies..."
pacman -D $deplist
if [ "$?" = "127" ]; then
error "Failed to install missing dependencies."
exit 1
fi
# TODO: check deps again to make sure they were resolved
elif [ "$DEP_SRC" = "1" ]; then
# install missing deps by building them from source.
# we look for each package name in $ABSROOT and build it.
if [ "$ABSROOT" = "" ]; then
error "The ABSROOT environment variable is not defined."
exit 1
fi
# TODO: handle version comparators (eg, glibc>=2.2.5)
msg "Building missing dependencies..."
for dep in $deplist; do
candidates=`find $ABSROOT -type d -name "$dep"`
if [ "$candidates" = "" ]; then
error "Could not find \"$dep\" under $ABSROOT"
exit 1
fi
success=0
for pkgdir in $candidates; do
if [ -f $pkgdir/PKGBUILD ]; then
cd $pkgdir
if [ "$RMDEPS" = "1" ]; then
makepkg -i -c -b -r -w $PKGDEST
else
makepkg -i -c -b -w $PKGDEST
fi
if [ $? -eq 0 ]; then
success=1
break
fi
fi
done
if [ "$success" = "0" ]; then
error "Failed to build \"$dep\""
exit 1
fi
done
# TODO: check deps again to make sure they were resolved
else
missingdeps=1
fi
elif [ "$deplist" != "" -a $haveperm -eq 0 ]; then
if [ "$DEP_SRC" = "1" -o "$DEP_BIN" = "1" ]; then
warning "Cannot auto-install missing dependencies as a normal user!"
plain "Run makepkg as root to resolve dependencies automatically."
fi
missingdeps=1
fi
return $missingdeps
}
usage() {
echo "makepkg version $myver"
echo "usage: $0 [options]"
echo "options:"
echo " -b, --builddeps Build missing dependencies from source"
echo " -c, --clean Clean up work files after build"
echo " -C, --cleancache Clean up source files from the cache"
echo " -d, --nodeps Skip all dependency checks"
echo " -e, --noextract Do not extract source files (use existing src/ dir)"
echo " -f, --force Overwrite existing package"
echo " -g, --genmd5 Generate MD5sums for source files"
echo " -h, --help This help"
echo " -i, --install Install package after successful build"
echo " -j <jobs> Set MAKEFLAGS to \"-j<jobs>\" before building"
echo " -m, --nocolor Disable colorized output messages"
echo " -n, --nostrip Do not strip binaries/libraries"
echo " -o, --nobuild Download and extract files only"
echo " -p <buildscript> Use an alternate build script (instead of PKGBUILD)"
echo " -r, --rmdeps Remove installed dependencies after a successful build"
echo " -s, --syncdeps Install missing dependencies with pacman"
echo " -w <destdir> Write package to <destdir> instead of the working dir"
echo
echo " if -p is not specified, makepkg will look for a PKGBUILD"
echo " file in the current directory."
echo
}
# Options
CLEANUP=0
CLEANCACHE=0
INSTALL=0
GENMD5=0
DEP_BIN=0
DEP_SRC=0
NODEPS=0
FORCE=0
NOEXTRACT=0
NOSTRIP=0
NOBUILD=0
RMDEPS=0
BUILDSCRIPT="./PKGBUILD"
ARGLIST=$@
while [ "$#" -ne "0" ]; do
case $1 in
--clean) CLEANUP=1 ;;
--cleancache) CLEANCACHE=1 ;;
--syncdeps) DEP_BIN=1 ;;
--builddeps) DEP_SRC=1 ;;
--nodeps) NODEPS=1 ;;
--noextract) NOEXTRACT=1 ;;
--install) INSTALL=1 ;;
--force) FORCE=1 ;;
--nostrip) NOSTRIP=1 ;;
--nobuild) NOBUILD=1 ;;
--nocolor) USE_COLOR="n" ;;
--genmd5) GENMD5=1 ;;
--rmdeps) RMDEPS=1 ;;
--help)
usage
exit 0
;;
--*)
usage
exit 1
;;
-*)
while getopts "cCsbdehifgj:mnorp:w:-" opt; do
case $opt in
c) CLEANUP=1 ;;
C) CLEANCACHE=1 ;;
b) DEP_SRC=1 ;;
d) NODEPS=1 ;;
e) NOEXTRACT=1 ;;
f) FORCE=1 ;;
g) GENMD5=1 ;;
h)
usage
exit 0
;;
i) INSTALL=1 ;;
j) export MAKEFLAGS="-j$OPTARG" ;;
m) USE_COLOR="n" ;;
n) NOSTRIP=1 ;;
o) NOBUILD=1 ;;
p) BUILDSCRIPT=$OPTARG ;;
r) RMDEPS=1 ;;
s) DEP_BIN=1 ;;
w) PKGDEST=$OPTARG ;;
-)
OPTIND=0
break
;;
*)
usage
exit 1
;;
esac
done
;;
*)
true
;;
esac
shift
done
# convert a (possibly) relative path to absolute
cd $PKGDEST 2>/dev/null
if [ $? -ne 0 ]; then
error "Package destination directory does not exist or permission denied."
exit 1
fi
PKGDEST=`pwd`
cd $OLDPWD
if [ "$CLEANCACHE" = "1" ]; then
if [ "`id -u`" = "0" -a "$INFAKEROOT" != "1" ]; then
msg "Cleaning up source files from the cache."
rm -rf /var/cache/pacman/src/*
exit 0
else
error "You must be root to clean the cache."
exit 1
fi
fi
unset pkgname pkgver pkgrel pkgdesc url license groups provides md5sums force
unset replaces depends conflicts backup source install build makedepends
umask 0022
if [ ! -f $BUILDSCRIPT ]; then
error "$BUILDSCRIPT does not exist."
exit 1
fi
source $BUILDSCRIPT
# check for no-no's
if [ `echo $pkgver | grep '-'` ]; then
error "pkgver is not allowed to contain hyphens."
exit 1
fi
if [ `echo $pkgrel | grep '-'` ]; then
error "pkgrel is not allowed to contain hyphens."
exit 1
fi
if [ -f $PKGDEST/${pkgname}-${pkgver}-${pkgrel}.pkg.tar.gz -a "$FORCE" = "0" -a "$GENMD5" = "0" ]; then
if [ "$INSTALL" = "1" ]; then
warning "a package has already been built, installing existing package."
pacman --upgrade $PKGDEST/${pkgname}-${pkgver}-${pkgrel}.pkg.tar.gz
exit $?
else
error "a package has already been built. (use -f to overwrite)"
exit 1
fi
fi
# Enter the fakeroot environment if necessary. This will call the makepkg script again
# as the fake root user. We detect this by passing a sentinel option (-F) to makepkg
if [ "`id -u`" != "0" ]; then
if [ "$USE_FAKEROOT" = "y" -o "$USE_FAKEROOT" = "Y" ]; then
if [ `type -p fakeroot` ]; then
msg "Entering fakeroot environment"
fakeroot -- $0 -F $ARGLIST
exit $?
else
warning "Fakeroot is not installed. Building as an unprivileged user"
plain "will result in non-root ownership of the packaged files."
plain "Install the fakeroot package to correctly build as a non-root"
plain "user."
plain ""
sleep 1
fi
else
warning "Running makepkg as an unprivileged user will result in non-root"
plain "ownership of the packaged files. Try using the fakeroot"
plain "environment. (USE_FAKEROOT=y in makepkg.conf)"
plain ""
sleep 1
fi
fi
msg "Making package: $pkgname (`date`)"
unset deplist makedeplist
if [ `type -p pacman` -a "$NODEPS" = "0" ]; then
msg "Checking Runtime Dependencies..."
deplist=`checkdeps ${depends[@]}`
handledeps $deplist
if [ $? -gt 0 ]; then
exit 1
fi
msg "Checking Buildtime Dependencies..."
makedeplist=`checkdeps ${makedepends[@]}`
handledeps $makedeplist
if [ $? -gt 0 ]; then
exit 1
fi
elif [ "$NODEPS" = "1" ]; then
warning "skipping dependency checks."
else
warning "pacman was not found in PATH. skipping dependency checks."
fi
cd $startdir
# retrieve sources
msg "Retrieving Sources..."
mkdir -p src
cd $startdir/src
for netfile in ${source[@]}; do
file=`strip_url $netfile`
if [ -f ../$file ]; then
msg " Found $file in build dir"
cp ../$file .
elif [ -f /var/cache/pacman/src/$file ]; then
msg " Using local copy of $file"
cp /var/cache/pacman/src/$file .
else
# check for a download utility
if [ -z "$FTPAGENT" ]; then
error "FTPAGENT is not configured. Check the /etc/makepkg.conf file."
msg "Aborting..."
exit 1
fi
ftpclient=`echo $FTPAGENT | awk {'print $1'}`
if [ ! -x $ftpclient ]; then
error "ftpclient `basename $ftpclient` is not installed."
msg "Aborting..."
exit 1
fi
proto=`echo $netfile | sed 's|://.*||'`
if [ "$proto" != "ftp" -a "$proto" != "http" -a "$proto" != "https" ]; then
error "$netfile was not found in the build directory and is not a proper URL."
msg "Aborting..."
exit 1
fi
msg " Downloading $file"
$FTPAGENT $netfile 2>&1
if [ ! -f $file ]; then
error "Failed to download $file"
msg "Aborting..."
exit 1
fi
if [ "`id -u`" = "0" -a "$INFAKEROOT" != "1" ]; then
mkdir -p /var/cache/pacman/src && cp $file /var/cache/pacman/src
else
cp $file ..
fi
fi
done
if [ "$GENMD5" = "0" ]; then
if [ "$NOEXTRACT" = "1" ]; then
warning "Skipping source extraction -- using existing src/ tree"
warning "Skipping source integrity checks -- using existing src/ tree"
else
# MD5 validation
if [ ${#md5sums[@]} -ne ${#source[@]} ]; then
warning "MD5sums are missing or incomplete. Cannot verify source integrity."
#sleep 1
elif [ `type -p md5sum` ]; then
msg "Validating source files with MD5sums"
errors=0
idx=0
for netfile in ${source[@]}; do
file=`strip_url $netfile`
echo -n " $file ... " >&2
echo "${md5sums[$idx]} $file" | md5sum -c - >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "FAILED" >&2
errors=1
else
echo "Passed" >&2
fi
idx=$(($idx+1))
done
if [ $errors -gt 0 ]; then
error "One or more files did not pass the validity check!"
exit 1
fi
else
warning "The md5sum program is missing. Cannot verify source files!"
sleep 1
fi
# extract sources
msg "Extracting Sources..."
for netfile in ${source[@]}; do
unziphack=0
file=`strip_url $netfile`
unset cmd
case $file in
*.tar.gz|*.tar.Z|*.tgz)
cmd="tar --use-compress-program=gzip -xf $file" ;;
*.tar.bz2)
cmd="tar --use-compress-program=bzip2 -xf $file" ;;
*.tar)
cmd="tar -xf $file" ;;
*.zip)
unziphack=1
cmd="unzip -qqo $file" ;;
*.gz)
cmd="gunzip $file" ;;
*.bz2)
cmd="bunzip2 $file" ;;
esac
if [ "$cmd" != "" ]; then
msg " $cmd"
$cmd
if [ $? -ne 0 ]; then
# unzip will return a 1 as a warning, it is not an error
if [ "$unziphack" != "1" -o $? -ne 1 ]; then
error "Failed to extract $file"
msg "Aborting..."
exit 1
fi
fi
fi
done
fi
else
# generate md5 hashes
if [ ! `type -p md5sum` ]; then
error "Cannot find the md5sum program."
exit 1
fi
msg "Generating MD5sums for source files"
plain ""
ct=0
newline=0
numsrc=${#source[@]}
for netfile in ${source[@]}; do
file=`strip_url $netfile`
sum=`md5sum $file | cut -d' ' -f 1`
if [ $ct -eq 0 ]; then
echo -n "md5sums=("
else
if [ $newline -eq 0 ]; then
echo -n " "
fi
fi
echo -n "'$sum'"
ct=$(($ct+1))
if [ $ct -eq $numsrc ]; then
echo ')'
else
if [ $newline -eq 1 ]; then
echo '\'
newline=0
else
echo -n ' '
newline=1
fi
fi
done
plain ""
exit 0
fi
if [ "`id -u`" = "0" ]; then
# chown all source files to root.root
chown -R root.root $startdir/src
fi
# check for existing pkg directory
if [ -d $startdir/pkg ]; then
msg "Removing existing pkg/ directory..."
rm -rf $startdir/pkg
fi
mkdir -p $startdir/pkg
if [ "$NOBUILD" = "1" ]; then
msg "Sources are ready."
exit 0
fi
# use ccache if it's available
[ -d /usr/lib/ccache/bin ] && export PATH=/usr/lib/ccache/bin:$PATH
# build
msg "Starting build()..."
build 2>&1
if [ $? -gt 0 ]; then
error "Build Failed. Aborting..."
exit 2
fi
# remove info/doc files
cd $startdir
rm -rf pkg/usr/info pkg/usr/share/info
rm -rf pkg/usr/doc pkg/usr/share/doc
# move /usr/share/man files to /usr/man
if [ -d pkg/usr/share/man ]; then
mkdir -p pkg/usr/man
cp -a pkg/usr/share/man/* pkg/usr/man/
rm -rf pkg/usr/share/man
fi
# remove /usr/share directory if empty
if [ -d pkg/usr/share ]; then
if [ -z "`ls -1 pkg/usr/share`" ]; then
rm -r pkg/usr/share
fi
fi
# compress man pages
msg "Compressing man pages..."
find $startdir/pkg/{usr{,/local,/share},opt/*}/man -type f 2>/dev/null | while read i ; do
ext="${i##*.}"
fn="${i##*/}"
if [ "$ext" != "gz" -a "$ext" != "bz2" ]; then
# update symlinks to this manpage
find $startdir/pkg/{usr{,/local,/share},opt/*}/man -lname "$fn" 2> /dev/null | while read ln ; do
rm -f "$ln"
ln -sf "${fn}.gz" "${ln}.gz"
done
# compress the original
gzip -9 "$i"
fi
done
cd $startdir
# strip binaries
if [ "$NOSTRIP" = "0" ]; then
msg "Stripping debugging symbols from libraries..."
find pkg/{,usr,usr/local,opt/*}/lib -type f -not -name "*.dll" -not -name "*.exe" \
-exec /usr/bin/strip --strip-debug '{}' \; 2>&1 \
| grep -v "No such file" | grep -v "format not recognized"
msg "Stripping symbols from binaries..."
find pkg/{,usr,usr/local,opt/*}/{bin,sbin} -type f -not -name "*.dll" -not -name "*.exe" \
-exec /usr/bin/strip '{}' \; 2>&1 \
| grep -v "No such file" | grep -v "format not recognized"
fi
# get some package meta info
builddate=`LC_ALL= ; LANG= ; date -u "+%a %b %e %H:%M:%S %Y"`
if [ "$PACKAGER" != "" ]; then
packager="$PACKAGER"
else
packager="Arch Linux (http://www.archlinux.org)"
fi
size=`du -cb $startdir/pkg | tail -n 1 | awk '{print $1}'`
# write the .PKGINFO file
msg "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
echo "pkgdesc = $pkgdesc" >>.PKGINFO
echo "url = $url" >>.PKGINFO
echo "license = $license" >>.PKGINFO
echo "builddate = $builddate" >>.PKGINFO
echo "packager = $packager" >>.PKGINFO
echo "size = $size" >>.PKGINFO
if [ "$CARCH" != "" ]; then
echo "arch = $CARCH" >>.PKGINFO
fi
for it in "${replaces[@]}"; do
echo "replaces = $it" >>.PKGINFO
done
for it in "${groups[@]}"; do
echo "group = $it" >>.PKGINFO
done
for it in "${depends[@]}"; do
echo "depend = $it" >>.PKGINFO
done
for it in "${conflicts[@]}"; do
echo "conflict = $it" >>.PKGINFO
done
for it in "${provides[@]}"; do
echo "provides = $it" >>.PKGINFO
done
for it in "${backup[@]}"; do
echo "backup = $it" >>.PKGINFO
done
# check for an install script
if [ "$install" != "" ]; then
msg "Copying install script..."
cp $startdir/$install $startdir/pkg/.INSTALL
fi
# build a filelist
msg "Generating .FILELIST file..."
cd $startdir/pkg
tar cvf /dev/null * | sort >.FILELIST
# tar it up
msg "Compressing package..."
cd $startdir/pkg
if [ -f $startdir/pkg/.INSTALL ]; then
cmd="tar czvf $PKGDEST/$pkgname-$pkgver-$pkgrel.pkg.tar.gz .PKGINFO .FILELIST .INSTALL *"
else
cmd="tar czvf $PKGDEST/$pkgname-$pkgver-$pkgrel.pkg.tar.gz .PKGINFO .FILELIST *"
fi
$cmd | sort >../filelist
cd $startdir
if [ "$CLEANUP" = "1" ]; then
msg "Cleaning up..."
rm -rf src pkg filelist
fi
if [ "$RMDEPS" = "1" -a "`id -u`" = "0" -a "$INFAKEROOT" != "1" ]; then
msg "Removing installed dependencies..."
pacman -R $makedeplist $deplist
fi
msg "Finished making: $pkgname (`date`)"
if [ "$INSTALL" = "1" -a "`id -u`" = "0" -a "$INFAKEROOT" != "1" ]; then
msg "Running pacman --upgrade..."
pacman --upgrade $PKGDEST/${pkgname}-${pkgver}-${pkgrel}.pkg.tar.gz
exit $?
fi
exit 0

143
scripts/makeworld Executable file
View File

@ -0,0 +1,143 @@
#!/bin/bash
#
# makeworld
#
# Copyright (c) 2002-2004 by Judd Vinet <jvinet@zeroflux.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
# USA.
#
toplevel=`pwd`
version="2.9.2"
usage() {
echo "makeworld version $version"
echo "usage: $0 [options] <destdir> <category> [category] ..."
echo "options:"
echo " -b, --builddeps Build missing dependencies from source"
echo " -c, --clean Clean up work files after build"
echo " -d, --nodeps Skip all dependency checks"
echo " -f, --force Overwrite existing packages"
echo " -i, --install Install package after successful build"
echo " -h, --help This help"
echo " -r, --rmdeps Remove installed dependencies after a successful build"
echo " -s, --syncdeps Install missing dependencies with pacman"
echo
echo " where <category> is one or more directory names under the ABS root"
echo " eg: makeworld -c /packages base lib editors"
echo
echo " this should be run from the toplevel directory of ABS (usually /var/abs)"
}
if [ $# -lt 2 ]; then
usage
exit 1
fi
MAKEPKG_OPTS=
for arg in $*; do
case $arg in
--clean) MAKEPKG_OPTS="$MAKEPKG_OPTS -c" ;;
--install) MAKEPKG_OPTS="$MAKEPKG_OPTS -i" ;;
--syncdeps) MAKEPKG_OPTS="$MAKEPKG_OPTS -s" ;;
--builddeps) MAKEPKG_OPTS="$MAKEPKG_OPTS -b" ;;
--nodeps) MAKEPKG_OPTS="$MAKEPKG_OPTS -d" ;;
--force) MAKEPKG_OPTS="$MAKEPKG_OPTS -f" ;;
--rmdeps) MAKEPKG_OPTS="$MAKEPKG_OPTS -r" ;;
--help)
usage
exit 0
;;
--*)
usage
exit 1
;;
-*)
while getopts "chisbdfr-" opt; do
case $opt in
c) MAKEPKG_OPTS="$MAKEPKG_OPTS -c" ;;
i) MAKEPKG_OPTS="$MAKEPKG_OPTS -i" ;;
s) MAKEPKG_OPTS="$MAKEPKG_OPTS -s" ;;
b) MAKEPKG_OPTS="$MAKEPKG_OPTS -b" ;;
d) MAKEPKG_OPTS="$MAKEPKG_OPTS -d" ;;
f) MAKEPKG_OPTS="$MAKEPKG_OPTS -f" ;;
r) MAKEPKG_OPTS="$MAKEPKG_OPTS -r" ;;
h)
usage
exit 0
;;
-)
OPTIND=0
break
;;
esac
done
;;
*)
dest=$arg
shift
break
;;
esac
shift
if [ "$dest" != "" ]; then
break
fi
done
if [ "$dest" = "" ]; then
usage
exit 1
fi
# convert a (possibly) relative path to absolute
cd $dest
dest=`pwd`
cd - &>/dev/null
sd=`date +"[%b %d %H:%M]"`
for category in $*; do
for port in `find $toplevel/$category -maxdepth 1 -mindepth 1 -type d | sort`; do
cd $port
if [ -f PKGBUILD ]; then
. PKGBUILD
buildstatus=0
if [ ! -f $dest/$pkgname-$pkgver-$pkgrel.pkg.tar.gz ]; then
makepkg $MAKEPKG_OPTS -m -w $dest 2>>$toplevel/makepkg.log
if [ $? -gt 0 ]; then
buildstatus=2
else
buildstatus=1
fi
fi
d=`date +"[%b %d %H:%M]"`
echo -n "$d " >>$toplevel/build.log
case $buildstatus in
0) echo "$pkgname already built -- skipping" >>$toplevel/build.log ;;
1) echo "$pkgname was built successfully" >>$toplevel/build.log ;;
2) echo "$pkgname build failed" >>$toplevel/build.log ;;
esac
fi
done
done
ed=`date +"[%b %d %H:%M]"`
echo "makeworld complete." >>$toplevel/build.log
echo " started: $sd" >>$toplevel/build.log
echo " finished: $ed" >>$toplevel/build.log
exit 0

231
scripts/updatesync Executable file
View File

@ -0,0 +1,231 @@
#!/bin/bash
#
# updatesync
#
# Copyright (c) 2004 by Jason Chu <jason@archlinux.org>
# Derived from gensync (c) 2002-2004 Judd Vinet <jvinet@zeroflux.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
# USA.
#
myver='2.9.2'
usage() {
echo "updatesync $myver"
echo "usage: $0 <action> <destfile> <option> [package_directory]"
echo
echo "updatesync will update a sync database by reading a PKGBUILD and"
echo "modifying the destfile. updatesync updates the database in a temporary"
echo "directory and then compresses it to <destfile>."
echo
echo "There are two types of actions:"
echo
echo "upd - Will update a package's entry or create it if it doesn't exist."
echo " It takes the package's PKGBUILD as an option."
echo "del - Will remove a package's entry from the db."
echo " It takes the package's name as an option."
echo
echo "updatesync will calculate md5sums of packages in the same directory as"
echo "<destfile>, unless an alternate [package_directory] is specified."
echo
echo "example: updatesync upd /home/mypkgs/custom.db.tar.gz PKGBUILD"
echo
echo
exit 0
}
die()
{
echo "updatesync: $*" >&2
rm -rf $ustmpdir
exit 1
}
get_md5checksum()
{
if [ "$pkgdir" != "" ]; then
pkgfile="$pkgdir/$pkgname-$pkgver-$pkgrel.pkg.tar.gz"
else
pkgfile="$destdir/$pkgname-$pkgver-$pkgrel.pkg.tar.gz"
fi
if [ -f $pkgfile ]; then
md5line=`md5sum $pkgfile`
[ ! -z "$md5line" ] && pkgmd5sum=${md5line% *}
echo $pkgmd5sum
fi
return 0
}
db_write_entry()
{
unset pkgname pkgver pkgrel pkgdesc force
unset groups replaces provides depends conflicts
source $1 || return 1
cd $ustmpdir
mkdir $pkgname-$pkgver-$pkgrel || return 1
cd $pkgname-$pkgver-$pkgrel
# desc
: >desc
echo "%NAME%" >>desc
echo "$pkgname" >>desc
echo "" >>desc
echo "%VERSION%" >>desc
echo "$pkgver-$pkgrel" >>desc
echo "" >>desc
echo "%DESC%" >>desc
echo "$pkgdesc" >>desc
echo "" >>desc
echo "%CSIZE%" >>desc
echo "$csize" >>desc
echo "" >>desc
if [ ! -z $pkgmd5sum ]; then
echo "%MD5SUM%" >>desc
echo "$pkgmd5sum" >>desc
echo "" >>desc
fi
if [ ${#groups[*]} -gt 0 ]; then
echo "%GROUPS%" >>desc
for it in "${groups[@]}"; do
echo "$it" >>desc
done
echo "" >>desc
fi
if [ ${#replaces[*]} -gt 0 ]; then
echo "%REPLACES%" >>desc
for it in "${replaces[@]}"; do
echo "$it" >>desc
done
echo "" >>desc
fi
if [ "$force" = "y" -o "$force" = "Y" ]; then
echo "%FORCE%" >>desc
echo "" >>desc
fi
# depends
: >depends
if [ ${#depends[*]} -gt 0 ]; then
echo "%DEPENDS%" >>depends
for it in "${depends[@]}"; do
echo "$it" >>depends
done
echo "" >>depends
fi
if [ ${#conflicts[*]} -gt 0 ]; then
echo "%CONFLICTS%" >>depends
for it in "${conflicts[@]}"; do
echo "$it" >>depends
done
echo "" >>depends
fi
if [ ${#provides[*]} -gt 0 ]; then
echo "%PROVIDES%" >>depends
for it in "${provides[@]}"; do
echo "$it" >>depends
done
echo "" >>depends
fi
}
delete_entry()
{
echo $1 | grep PKGBUILD 2>&1 >/dev/null
if [ $? -eq 0 ]; then
source $1
else
pkgname=$1
fi
for i in *; do
if [ "${i%-*-*}" = "$pkgname" ]; then
echo "updatesync: deleting $i" >&2
rm -rf $i
fi
done
}
if [ $# -lt 3 ]; then
usage
exit 0
fi
if [ "$1" = "-h" -o "$1" = "--help" ]; then
usage
exit 0
fi
action=$1
pkgdb=$2
option=$3
curdir="`pwd`"
pkgdir=$curdir
if [ "$4" != "" ]; then
pkgdir=$4
fi
if [ "$action" != "upd" -a "$action" != "del" ]; then
usage
exit 1
fi
ustmpdir=$(mktemp -d /tmp/updatesync.XXXXXXXXXX) || exit 1
cd $ustmpdir
if [ ! -f $pkgdb ]; then
if [ ! -f $curdir/$pkgdb ]; then
echo "updatesync: $pkgdb not found"
exit 1
fi
pkgdb=$curdir/$pkgdb
fi
if [ "$action" = "upd" -a ! -f $option ]; then
if [ ! -f $curdir/$option ]; then
echo "updatesync: $option not found"
exit 1
fi
option=$curdir/$option
fi
echo "updatesync: uncompressing to $ustmpdir..." >&2
tar -xzf $pkgdb || die "error uncompressing $pkgdb"
if [ "$action" = "upd" ]; then
# INSERT / UPDATE
delete_entry $option
source $option || die "errors parsing $option"
if [ "$pkgdir" != "" ]; then
pkgfile="$pkgdir/$pkgname-$pkgver-$pkgrel.pkg.tar.gz"
else
pkgfile="$destdir/$pkgname-$pkgver-$pkgrel.pkg.tar.gz"
fi
[ -f $pkgfile ] || die "missing package file: $pkgfile"
csize=`du -b $pkgfile | cut -f1`
pkgmd5sum=`get_md5checksum $pkgfile`
[ -z $pkgmd5sum ] && die "error generating checksum for $pkgfile"
echo "updatesync: creating entry for $option" >&2
db_write_entry $option || die "error writing entry for $option"
else
# DELETE
delete_entry $option
fi
echo "updatesync: compressing to $pkgdb..." >&2
cd $ustmpdir
tar c * | gzip -9 >$pkgdb || die "error writing to $pkgdb"
cd $curdir
rm -rf $ustmpdir
exit 0

39
src/pacman/Makefile Normal file
View File

@ -0,0 +1,39 @@
CC=gcc
CFLAGS=-g -Wall -D_GNU_SOURCE -I. -I../.. -I../../lib/libalpm -I../../lib/libftp
LDFLAGS=-L../../lib/libalpm -lalpm -L../../lib/libftp -lftp -ltar -lz
AR=ar rc
RAN=ranlib
OBJECTS=util.o \
list.o \
package.o \
db.o \
download.o \
add.o \
remove.o \
upgrade.o \
query.o \
sync.o \
conf.o \
pacman.o
all: pacman
%.o: %.c %.h
$(CC) -c $(CFLAGS) -o $@ $<
pacman: $(OBJECTS) ../../lib/libalpm/libalpm.a
$(CC) $(OBJECTS) -o $@ $(CFLAGS) $(LDFLAGS)
# $(CC) $(OBJECTS) -o $@.static $(CFLAGS) $(LDFLAGS)
clean:
rm -f *.o *~ core
rm -f pacman pacman.static convertdb vercmp
install: pacman vercmp convertdb
$(INSTALL) -D -m0755 pacman $(DESTDIR)$(BINDIR)/pacman
$(INSTALL) -D -m0755 pacman.static $(DESTDIR)$(BINDIR)/pacman.static
$(INSTALL) -D -m0755 vercmp $(DESTDIR)$(BINDIR)/vercmp
$(INSTALL) -D -m0755 convertdb $(DESTDIR)$(BINDIR)/convertdb

130
src/pacman/add.c Normal file
View File

@ -0,0 +1,130 @@
/*
* add.c
*
* Copyright (c) 2002-2005 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <alpm.h>
/* pacman */
#include "list.h"
#include "download.h"
#include "pacman.h"
extern unsigned char pmo_upgrade;
extern unsigned char pmo_flags;
int pacman_add(list_t *targets)
{
PM_LIST *data;
list_t *i;
if(targets == NULL) {
return(0);
}
/* Check for URL targets and process them
*/
for(i = targets; i; i = i->next) {
if(strstr(i->data, "://")) {
char *str = fetch_pkgurl(i->data);
if(str == NULL) {
return(1);
} else {
free(i->data);
i->data = str;
}
}
}
/* Step 1: create a new transaction
*/
if(alpm_trans_init((pmo_upgrade == 0) ? PM_TRANS_TYPE_ADD : PM_TRANS_TYPE_UPGRADE,
pmo_flags, cb_trans) == -1) {
ERR(NL, "%s\n", alpm_strerror(pm_errno));
return(1);
}
/* and add targets to it */
MSG(NL, "loading package data... ");
for(i = targets; i; i = i->next) {
if(alpm_trans_addtarget(i->data) == -1) {
ERR(NL, "failed to add target '%s' (%s)\n", (char *)i->data, alpm_strerror(pm_errno));
return(1);
}
}
MSG(CL, "done");
/* Step 2: "compute" the transaction based on targets and flags
*/
if(alpm_trans_prepare(&data) == -1) {
PM_LIST *i;
ERR(NL, "failed to prepare transaction (%s)\n", alpm_strerror(pm_errno));
switch(pm_errno) {
case PM_ERR_UNSATISFIED_DEPS:
for(i = alpm_list_first(data); i; i = alpm_list_next(i)) {
pmdepmissing_t *miss = alpm_list_getdata(i);
MSG(NL, ":: %s: requires %s", miss->target, miss->depend.name);
switch(miss->depend.mod) {
case PM_DEP_EQ: MSG(CL, "=%s", miss->depend.version); break;
case PM_DEP_GE: MSG(CL, ">=%s", miss->depend.version); break;
case PM_DEP_LE: MSG(CL, "<=%s", miss->depend.version); break;
}
MSG(CL, "\n");
}
alpm_list_free(data);
break;
case PM_ERR_CONFLICTING_DEPS:
for(i = alpm_list_first(data); i; i = alpm_list_next(i)) {
pmdepmissing_t *miss = alpm_list_getdata(i);
MSG(NL, ":: %s: conflicts with %s",
miss->target, miss->depend.name, miss->depend.name);
}
alpm_list_free(data);
break;
case PM_ERR_FILE_CONFLICTS:
for(i = alpm_list_first(data); i; i = alpm_list_next(i)) {
MSG(NL, ":: %s\n", (char *)alpm_list_getdata(i));
}
alpm_list_free(data);
MSG(NL, "\nerrors occurred, no packages were upgraded.\n\n");
break;
default:
break;
}
alpm_trans_release();
return(1);
}
/* Step 3: actually perform the installation
*/
if(alpm_trans_commit() == -1) {
ERR(NL, "failed to commit transaction (%s)\n", alpm_strerror(pm_errno));
return(1);
}
return(0);
}
/* vim: set ts=2 sw=2 noet: */

28
src/pacman/add.h Normal file
View File

@ -0,0 +1,28 @@
/*
* add.h
*
* Copyright (c) 2002-2005 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 _PM_ADD_H
#define _PM_ADD_H
int pacman_add(list_t *targets);
#endif /* _PM_ADD_H */
/* vim: set ts=2 sw=2 noet: */

308
src/pacman/conf.c Normal file
View File

@ -0,0 +1,308 @@
/*
* conf.c
*
* Copyright (c) 2002-2005 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <alpm.h>
/* pacman */
#include "util.h"
#include "list.h"
#include "sync.h"
#include "download.h"
#include "pacman.h"
#define min(X, Y) ((X) < (Y) ? (X) : (Y))
extern list_t *pmo_holdpkg;
extern char *pmo_proxyhost;
extern unsigned short pmo_proxyport;
extern unsigned short pmo_nopassiveftp;
extern list_t *pmc_syncs;
int parseconfig(char *file)
{
FILE *fp = NULL;
char line[PATH_MAX+1];
char *ptr = NULL;
char *key = NULL;
int linenum = 0;
char section[256] = "";
sync_t *sync = NULL;
fp = fopen(file, "r");
if(fp == NULL) {
perror(file);
return(1);
}
while(fgets(line, PATH_MAX, fp)) {
linenum++;
strtrim(line);
if(strlen(line) == 0 || line[0] == '#') {
continue;
}
if(line[0] == '[' && line[strlen(line)-1] == ']') {
/* new config section */
ptr = line;
ptr++;
strncpy(section, ptr, min(255, strlen(ptr)-1));
section[min(255, strlen(ptr)-1)] = '\0';
vprint("config: new section '%s'\n", section);
if(!strlen(section)) {
ERR(NL, "config: line %d: bad section name\n", linenum);
return(1);
}
if(!strcmp(section, "local")) {
ERR(NL, "config: line %d: '%s' is reserved and cannot be used as a package tree\n",
linenum, section);
return(1);
}
if(strcmp(section, "options")) {
list_t *i;
int found = 0;
for(i = pmc_syncs; i && !found; i = i->next) {
sync = (sync_t *)i->data;
if(!strcmp(sync->treename, section)) {
found = 1;
}
}
if(!found) {
/* start a new sync record */
sync = (sync_t *)malloc(sizeof(sync_t));
if(sync == NULL) {
ERR(NL, "could not allocate %d bytes\n", sizeof(sync_t));
return(1);
}
sync->treename = strdup(section);
sync->servers = NULL;
pmc_syncs = list_add(pmc_syncs, sync);
}
}
} else {
/* directive */
ptr = line;
key = strsep(&ptr, "=");
if(key == NULL) {
ERR(NL, "config: line %d: syntax error\n", linenum);
return(1);
}
strtrim(key);
key = strtoupper(key);
if(!strlen(section) && strcmp(key, "INCLUDE")) {
ERR(NL, "config: line %d: all directives must belong to a section\n", linenum);
return(1);
}
if(ptr == NULL) {
if(!strcmp(key, "NOPASSIVEFTP")) {
pmo_nopassiveftp = 1;
vprint("config: nopassiveftp\n");
} else if(!strcmp(key, "USESYSLOG")) {
if(alpm_set_option(PM_OPT_USESYSLOG, (long)1) == -1) {
ERR(NL, "failed to set option USESYSLOG (%s)\n", alpm_strerror(pm_errno));
return(1);
}
vprint("config: usesyslog\n");
} else {
ERR(NL, "config: line %d: syntax error\n", linenum);
return(1);
}
} else {
strtrim(ptr);
if(!strcmp(key, "INCLUDE")) {
char conf[PATH_MAX];
strncpy(conf, ptr, PATH_MAX);
vprint("config: including %s\n", conf);
parseconfig(conf);
} else if(!strcmp(section, "options")) {
if(!strcmp(key, "NOUPGRADE")) {
char *p = ptr;
char *q;
while((q = strchr(p, ' '))) {
*q = '\0';
if(alpm_set_option(PM_OPT_NOUPGRADE, (long)p) == -1) {
ERR(NL, "failed to set option NOUPGRADE (%s)\n", alpm_strerror(pm_errno));
return(1);
}
vprint("config: noupgrade: %s\n", p);
p = q;
p++;
}
if(alpm_set_option(PM_OPT_NOUPGRADE, (long)p) == -1) {
ERR(NL, "failed to set option NOUPGRADE (%s)\n", alpm_strerror(pm_errno));
return(1);
}
vprint("config: noupgrade: %s\n", p);
} else if(!strcmp(key, "IGNOREPKG")) {
char *p = ptr;
char *q;
while((q = strchr(p, ' '))) {
*q = '\0';
if(alpm_set_option(PM_OPT_IGNOREPKG, (long)p) == -1) {
ERR(NL, "failed to set option IGNOREPKG (%s)\n", alpm_strerror(pm_errno));
return(1);
}
vprint("config: ignorepkg: %s\n", p);
p = q;
p++;
}
if(alpm_set_option(PM_OPT_IGNOREPKG, (long)p) == -1) {
ERR(NL, "failed to set option IGNOREPKG (%s)\n", alpm_strerror(pm_errno));
return(1);
}
vprint("config: ignorepkg: %s\n", p);
} else if(!strcmp(key, "HOLDPKG")) {
char *p = ptr;
char *q;
while((q = strchr(p, ' '))) {
*q = '\0';
pmo_holdpkg = list_add(pmo_holdpkg, strdup(p));
vprint("config: holdpkg: %s\n", p);
p = q;
p++;
}
pmo_holdpkg = list_add(pmo_holdpkg, strdup(p));
vprint("config: holdpkg: %s\n", p);
} else if(!strcmp(key, "DBPATH")) {
/* shave off the leading slash, if there is one */
if(*ptr == '/') {
ptr++;
}
if(alpm_set_option(PM_OPT_DBPATH, (long)ptr) == -1) {
ERR(NL, "failed to set option DBPATH (%s)\n", alpm_strerror(pm_errno));
return(1);
}
vprint("config: dbpath: %s\n", ptr);
} else if (!strcmp(key, "LOGFILE")) {
if(alpm_set_option(PM_OPT_LOGFILE, (long)ptr) == -1) {
ERR(NL, "failed to set option LOGFILE (%s)\n", alpm_strerror(pm_errno));
return(1);
}
vprint("config: log file: %s\n", ptr);
} else if (!strcmp(key, "PROXYSERVER")) {
char *p;
if(pmo_proxyhost) {
FREE(pmo_proxyhost);
}
p = strstr(ptr, "://");
if(p) {
p += 3;
if(p == NULL || *p == '\0') {
ERR(NL, "config: line %d: bad server location\n", linenum);
return(1);
}
ptr = p;
}
pmo_proxyhost = strndup(ptr, PATH_MAX);
vprint("config: proxyserver: %s\n", pmo_proxyhost);
} else if (!strcmp(key, "PROXYPORT")) {
pmo_proxyport = (unsigned short)atoi(ptr);
vprint("config: proxyport: %u\n", pmo_proxyport);
} else if (!strcmp(key, "INCLUDE")) {
/* ORE
TBD */
} else {
ERR(NL, "config: line %d: syntax error\n", linenum);
return(1);
}
} else {
if(!strcmp(key, "SERVER")) {
/* parse our special url */
server_t *server;
char *p;
if((server = (server_t *)malloc(sizeof(server_t))) == NULL) {
ERR(NL, "could not allocate %d bytes\n", sizeof(server_t));
return(1);
}
server->server = server->path = NULL;
server->protocol = NULL;
p = strstr(ptr, "://");
if(p == NULL) {
ERR(NL, "config: line %d: bad server location\n", linenum);
return(1);
}
*p = '\0';
p++; p++; p++;
if(p == NULL || *p == '\0') {
ERR(NL, "config: line %d: bad server location\n", linenum);
return(1);
}
server->protocol = strdup(ptr);
if(!strcmp(server->protocol, "ftp") || !strcmp(server->protocol, "http")) {
char *slash;
/* split the url into domain and path */
slash = strchr(p, '/');
if(slash == NULL) {
/* no path included, default to / */
server->path = strdup("/");
} else {
/* add a trailing slash if we need to */
if(slash[strlen(slash)-1] == '/') {
server->path = strdup(slash);
} else {
if((server->path = (char *)malloc(strlen(slash)+2)) == NULL) {
ERR(NL, "could not allocate %d bytes\n", sizeof(strlen(slash+2)));
return(1);
}
sprintf(server->path, "%s/", slash);
}
*slash = '\0';
}
server->server = strdup(p);
} else if(!strcmp(server->protocol, "file")){
/* add a trailing slash if we need to */
if(p[strlen(p)-1] == '/') {
server->path = strdup(p);
} else {
server->path = (char *)malloc(strlen(p)+2);
if(server->path == NULL) {
ERR(NL, "could not allocate %d bytes\n", sizeof(strlen(p+2)));
return(1);
}
sprintf(server->path, "%s/", p);
}
} else {
ERR(NL, "config: line %d: protocol %s is not supported\n", linenum, ptr);
return(1);
}
/* add to the list */
vprint("config: %s: server: %s %s %s\n", section, server->protocol, server->server, server->path);
sync->servers = list_add(sync->servers, server);
} else {
ERR(NL, "config: line %d: syntax error\n", linenum);
return(1);
}
}
line[0] = '\0';
}
}
}
fclose(fp);
return(0);
}
/* vim: set ts=2 sw=2 noet: */

28
src/pacman/conf.h Normal file
View File

@ -0,0 +1,28 @@
/*
* conf.h
*
* Copyright (c) 2002-2005 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 _PM_CONF_H
#define _PM_CONF_H
int parseconfig(char *file);
#endif /* _PM_CONF_H */
/* vim: set ts=2 sw=2 noet: */

98
src/pacman/db.c Normal file
View File

@ -0,0 +1,98 @@
/*
* db.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <alpm.h>
/* pacman */
#include "util.h"
#include "list.h"
#include "sync.h"
#include "db.h"
int db_search(PM_DB *db, char *treename, char *needle)
{
PM_LIST *lp;
char *targ;
targ = strdup(needle);
strtoupper(targ);
for(lp = alpm_db_getpkgcache(db); lp; lp = alpm_list_next(lp)) {
PM_PKG *pkg = alpm_list_getdata(lp);
char *haystack;
char *pkgname, *pkgdesc;
int match = 0;
pkgname = alpm_pkg_getinfo(pkg, PM_PKG_NAME);
pkgdesc = alpm_pkg_getinfo(pkg, PM_PKG_DESC);
/* check name */
haystack = strdup(pkgname);
strtoupper(haystack);
if(strstr(haystack, targ)) {
match = 1;
}
FREE(haystack);
/* check description */
if(!match) {
haystack = strdup(pkgdesc);
strtoupper(haystack);
if(strstr(haystack, targ)) {
match = 1;
}
FREE(haystack);
}
/* check provides */
if(!match) {
PM_LIST *m;
for(m = alpm_pkg_getinfo(pkg, PM_PKG_PROVIDES); m; m = alpm_list_next(m)) {
haystack = strdup(alpm_list_getdata(m));
strtoupper(haystack);
if(strstr(haystack, targ)) {
match = 1;
}
FREE(haystack);
}
}
if(match) {
printf("%s/%s %s\n ", treename, pkgname, (char *)alpm_pkg_getinfo(pkg, PM_PKG_VERSION));
indentprint(pkgdesc, 4);
printf("\n");
}
}
FREE(targ);
return(0);
}
/* vim: set ts=2 sw=2 noet: */

28
src/pacman/db.h Normal file
View File

@ -0,0 +1,28 @@
/*
* db.h
*
* Copyright (c) 2002-2005 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 _PM_DB_H
#define _PM_DB_H
int db_search(PM_DB *db, char *treename, char *needle);
#endif /* _PM_DB_H */
/* vim: set ts=2 sw=2 noet: */

467
src/pacman/download.c Normal file
View File

@ -0,0 +1,467 @@
/*
* download.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/time.h>
#include <ftplib.h>
#include <alpm.h>
/* pacman */
#include "list.h"
#include "download.h"
#include "pacman.h"
/* progress bar */
static char sync_fnm[25];
static int offset;
static struct timeval t0, t;
static float rate;
static int xfered1;
static unsigned char eta_h, eta_m, eta_s;
/* pacman options */
extern char *pmo_root;
extern char *pmo_dbpath;
extern char *pmo_proxyhost;
extern char *pmo_xfercommand;
extern unsigned short pmo_proxyport;
extern unsigned short pmo_nopassiveftp;
extern int maxcols;
static int log_progress(netbuf *ctl, int xfered, void *arg)
{
int fsz = *(int*)arg;
int pct = ((float)(xfered+offset) / fsz) * 100;
int i, cur;
struct timeval t1;
float timediff;
gettimeofday(&t1, NULL);
if(xfered+offset == fsz) {
t = t0;
}
timediff = t1.tv_sec-t.tv_sec + (float)(t1.tv_usec-t.tv_usec) / 1000000;
if(xfered+offset == fsz) {
/* average download rate */
rate = xfered / (timediff * 1024);
/* total download time */
eta_s = (int)timediff;
eta_h = eta_s / 3600;
eta_s -= eta_h * 3600;
eta_m = eta_s / 60;
eta_s -= eta_m * 60;
} else if(timediff > 1) {
/* we avoid computing the rate & ETA on too small periods of time, so that
results are more significant */
rate = (xfered-xfered1) / (timediff * 1024);
xfered1 = xfered;
gettimeofday(&t, NULL);
eta_s = (fsz-(xfered+offset)) / (rate * 1024);
eta_h = eta_s / 3600;
eta_s -= eta_h * 3600;
eta_m = eta_s / 60;
eta_s -= eta_m * 60;
}
printf(" %s [", sync_fnm);
cur = (int)((maxcols-64)*pct/100);
for(i = 0; i < maxcols-64; i++) {
(i < cur) ? printf("#") : printf(" ");
}
if(rate > 1000) {
printf("] %3d%% %6dK %6.0fK/s %02d:%02d:%02d\r", pct, ((xfered+offset) / 1024), rate, eta_h, eta_m, eta_s);
} else {
printf("] %3d%% %6dK %6.1fK/s %02d:%02d:%02d\r", pct, ((xfered+offset) / 1024), rate, eta_h, eta_m, eta_s);
}
fflush(stdout);
return(1);
}
static int copyfile(char *src, char *dest)
{
FILE *in, *out;
size_t len;
char buf[4097];
in = fopen(src, "r");
if(in == NULL) {
return(1);
}
out = fopen(dest, "w");
if(out == NULL) {
return(1);
}
while((len = fread(buf, 1, 4096, in))) {
fwrite(buf, 1, len, out);
}
fclose(in);
fclose(out);
return(0);
}
int downloadfiles(list_t *servers, const char *localpath, list_t *files)
{
int fsz;
netbuf *control = NULL;
list_t *lp;
int done = 0;
list_t *complete = NULL;
list_t *i;
if(files == NULL) {
return(0);
}
for(i = servers; i && !done; i = i->next) {
server_t *server = (server_t*)i->data;
if(!pmo_xfercommand && strcmp(server->protocol, "file")) {
if(!strcmp(server->protocol, "ftp") && !pmo_proxyhost) {
FtpInit();
vprint("Connecting to %s:21\n", server->server);
if(!FtpConnect(server->server, &control)) {
fprintf(stderr, "error: cannot connect to %s\n", server->server);
continue;
}
if(!FtpLogin("anonymous", "arch@guest", control)) {
fprintf(stderr, "error: anonymous login failed\n");
FtpQuit(control);
continue;
}
if(!FtpChdir(server->path, control)) {
fprintf(stderr, "error: could not cwd to %s: %s\n", server->path,
FtpLastResponse(control));
continue;
}
if(!pmo_nopassiveftp) {
if(!FtpOptions(FTPLIB_CONNMODE, FTPLIB_PASSIVE, control)) {
fprintf(stderr, "warning: failed to set passive mode\n");
}
} else {
vprint("FTP passive mode not set\n");
}
} else if(pmo_proxyhost) {
char *host;
unsigned port;
host = (pmo_proxyhost) ? pmo_proxyhost : server->server;
port = (pmo_proxyhost) ? pmo_proxyport : 80;
if(strchr(host, ':')) {
vprint("Connecting to %s\n", host);
} else {
vprint("Connecting to %s:%u\n", host, port);
}
if(!HttpConnect(host, port, &control)) {
fprintf(stderr, "error: cannot connect to %s\n", host);
continue;
}
}
/* set up our progress bar's callback (and idle timeout) */
if(strcmp(server->protocol, "file") && control) {
FtpOptions(FTPLIB_CALLBACK, (long)log_progress, control);
FtpOptions(FTPLIB_IDLETIME, (long)1000, control);
FtpOptions(FTPLIB_CALLBACKARG, (long)&fsz, control);
FtpOptions(FTPLIB_CALLBACKBYTES, (10*1024), control);
}
}
/* get each file in the list */
for(lp = files; lp; lp = lp->next) {
char *fn = (char *)lp->data;
if(list_is_strin(fn, complete)) {
continue;
}
if(pmo_xfercommand && strcmp(server->protocol, "file")) {
int ret;
int usepart = 0;
char *ptr1, *ptr2;
char origCmd[PATH_MAX];
char parsedCmd[PATH_MAX] = "";
char url[PATH_MAX];
char cwd[PATH_MAX];
/* build the full download url */
snprintf(url, PATH_MAX, "%s://%s%s%s", server->protocol, server->server,
server->path, fn);
/* replace all occurrences of %o with fn.part */
strncpy(origCmd, pmo_xfercommand, sizeof(origCmd));
ptr1 = origCmd;
while((ptr2 = strstr(ptr1, "%o"))) {
usepart = 1;
ptr2[0] = '\0';
strcat(parsedCmd, ptr1);
strcat(parsedCmd, fn);
strcat(parsedCmd, ".part");
ptr1 = ptr2 + 2;
}
strcat(parsedCmd, ptr1);
/* replace all occurrences of %u with the download URL */
strncpy(origCmd, parsedCmd, sizeof(origCmd));
parsedCmd[0] = '\0';
ptr1 = origCmd;
while((ptr2 = strstr(ptr1, "%u"))) {
ptr2[0] = '\0';
strcat(parsedCmd, ptr1);
strcat(parsedCmd, url);
ptr1 = ptr2 + 2;
}
strcat(parsedCmd, ptr1);
/* cwd to the download directory */
getcwd(cwd, PATH_MAX);
if(chdir(localpath)) {
fprintf(stderr, "error: could not chdir to %s\n", localpath);
return(1);
}
/* execute the parsed command via /bin/sh -c */
vprint("running command: %s\n", parsedCmd);
ret = system(parsedCmd);
if(ret == -1) {
fprintf(stderr, "error running XferCommand: fork failed!\n");
return(1);
} else if(ret != 0) {
/* download failed */
vprint("XferCommand command returned non-zero status code (%d)\n", ret);
} else {
/* download was successful */
complete = list_add(complete, fn);
if(usepart) {
char fnpart[PATH_MAX];
/* rename "output.part" file to "output" file */
snprintf(fnpart, PATH_MAX, "%s.part", fn);
rename(fnpart, fn);
}
}
chdir(cwd);
} else {
char output[PATH_MAX];
int j, filedone = 0;
char *ptr;
struct stat st;
snprintf(output, PATH_MAX, "%s/%s.part", localpath, fn);
strncpy(sync_fnm, fn, 24);
/* drop filename extension */
ptr = strstr(fn, ".db.tar.gz");
if(ptr && (ptr-fn) < 24) {
sync_fnm[ptr-fn] = '\0';
}
ptr = strstr(fn, ".pkg.tar.gz");
if(ptr && (ptr-fn) < 24) {
sync_fnm[ptr-fn] = '\0';
}
for(j = strlen(sync_fnm); j < 24; j++) {
sync_fnm[j] = ' ';
}
sync_fnm[24] = '\0';
offset = 0;
/* ETA setup */
gettimeofday(&t0, NULL);
t = t0;
rate = 0;
xfered1 = 0;
eta_h = 0;
eta_m = 0;
eta_s = 0;
if(!strcmp(server->protocol, "ftp") && !pmo_proxyhost) {
if(!FtpSize(fn, &fsz, FTPLIB_IMAGE, control)) {
fprintf(stderr, "warning: failed to get filesize for %s\n", fn);
}
if(!stat(output, &st)) {
offset = (int)st.st_size;
if(!FtpRestart(offset, control)) {
fprintf(stderr, "warning: failed to resume download -- restarting\n");
/* can't resume: */
/* unlink the file in order to restart download from scratch */
unlink(output);
}
}
if(!FtpGet(output, fn, FTPLIB_IMAGE, control)) {
fprintf(stderr, "\nfailed downloading %s from %s: %s\n",
fn, server->server, FtpLastResponse(control));
/* we leave the partially downloaded file in place so it can be resumed later */
} else {
filedone = 1;
}
} else if(!strcmp(server->protocol, "http") || (pmo_proxyhost && strcmp(server->protocol, "file"))) {
char src[PATH_MAX];
char *host;
unsigned port;
if(!strcmp(server->protocol, "http") && !pmo_proxyhost) {
/* HTTP servers hang up after each request (but not proxies), so
* we have to re-connect for each file.
*/
host = (pmo_proxyhost) ? pmo_proxyhost : server->server;
port = (pmo_proxyhost) ? pmo_proxyport : 80;
if(strchr(host, ':')) {
vprint("Connecting to %s\n", host);
} else {
vprint("Connecting to %s:%u\n", host, port);
}
if(!HttpConnect(host, port, &control)) {
fprintf(stderr, "error: cannot connect to %s\n", host);
continue;
}
/* set up our progress bar's callback (and idle timeout) */
if(strcmp(server->protocol, "file") && control) {
FtpOptions(FTPLIB_CALLBACK, (long)log_progress, control);
FtpOptions(FTPLIB_IDLETIME, (long)1000, control);
FtpOptions(FTPLIB_CALLBACKARG, (long)&fsz, control);
FtpOptions(FTPLIB_CALLBACKBYTES, (10*1024), control);
}
}
if(!stat(output, &st)) {
offset = (int)st.st_size;
}
if(!pmo_proxyhost) {
snprintf(src, PATH_MAX, "%s%s", server->path, fn);
} else {
snprintf(src, PATH_MAX, "%s://%s%s%s", server->protocol, server->server, server->path, fn);
}
if(!HttpGet(server->server, output, src, &fsz, control, offset)) {
fprintf(stderr, "\nfailed downloading %s from %s: %s\n",
src, server->server, FtpLastResponse(control));
/* we leave the partially downloaded file in place so it can be resumed later */
} else {
filedone = 1;
}
} else if(!strcmp(server->protocol, "file")) {
char src[PATH_MAX];
snprintf(src, PATH_MAX, "%s%s", server->path, fn);
vprint("copying %s to %s/%s\n", src, localpath, fn);
/* local repository, just copy the file */
if(copyfile(src, output)) {
fprintf(stderr, "failed copying %s\n", src);
} else {
filedone = 1;
}
}
if(filedone) {
char completefile[PATH_MAX];
if(!strcmp(server->protocol, "file")) {
char out[56];
printf(" %s [", sync_fnm);
strncpy(out, server->path, 33);
printf("%s", out);
for(j = strlen(out); j < maxcols-64; j++) {
printf(" ");
}
fputs("] 100% LOCAL ", stdout);
} else {
log_progress(control, fsz-offset, &fsz);
}
complete = list_add(complete, fn);
/* rename "output.part" file to "output" file */
snprintf(completefile, PATH_MAX, "%s/%s", localpath, fn);
rename(output, completefile);
}
printf("\n");
fflush(stdout);
}
}
if(!pmo_xfercommand) {
if(!strcmp(server->protocol, "ftp") && !pmo_proxyhost) {
FtpQuit(control);
} else if(!strcmp(server->protocol, "http") || (pmo_proxyhost && strcmp(server->protocol, "file"))) {
HttpQuit(control);
}
}
if(list_count(complete) == list_count(files)) {
done = 1;
}
}
return(!done);
}
char *fetch_pkgurl(char *target)
{
char spath[PATH_MAX];
char url[PATH_MAX];
server_t *server;
list_t *servers = NULL;
list_t *files = NULL;
char *host, *path, *fn;
/* ORE
do not download the file if it exists in the current dir */
strncpy(url, target, PATH_MAX);
host = strstr(url, "://");
*host = '\0';
host += 3;
path = strchr(host, '/');
*path = '\0';
path++;
fn = strrchr(path, '/');
if(fn) {
*fn = '\0';
if(path[0] == '/') {
snprintf(spath, PATH_MAX, "%s/", path);
} else {
snprintf(spath, PATH_MAX, "/%s/", path);
}
fn++;
} else {
fn = path;
strcpy(spath, "/");
}
server = (server_t *)malloc(sizeof(server_t));
if(server == NULL) {
fprintf(stderr, "error: failed to allocate %d bytes\n", sizeof(server_t));
return(NULL);
}
server->protocol = url;
server->server = host;
server->path = spath;
servers = list_add(servers, server);
files = list_add(files, fn);
if(downloadfiles(servers, ".", files)) {
fprintf(stderr, "error: failed to download %s\n", target);
return(NULL);
}
FREELIST(servers);
files->data = NULL;
FREELIST(files);
/* return the target with the raw filename, no URL */
return(strndup(fn, PATH_MAX));
}
/* vim: set ts=2 sw=2 noet: */

38
src/pacman/download.h Normal file
View File

@ -0,0 +1,38 @@
/*
* download.h
*
* Copyright (c) 2002-2005 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 _PM_DOWNLOAD_H
#define _PM_DOWNLOAD_H
#include "list.h"
/* Servers */
typedef struct __server_t {
char *protocol;
char *server;
char *path;
} server_t;
int downloadfiles(list_t *servers, const char *localpath, list_t *files);
char *fetch_pkgurl(char *target);
#endif /* _PM_DOWNLOAD_H */
/* vim: set ts=2 sw=2 noet: */

176
src/pacman/list.c Normal file
View File

@ -0,0 +1,176 @@
/*
* list.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/* pacman */
#include "list.h"
extern int maxcols;
static list_t *list_last(list_t *list);
list_t *list_new()
{
list_t *list = NULL;
list = (list_t *)malloc(sizeof(list_t));
if(list == NULL) {
return(NULL);
}
list->data = NULL;
list->next = NULL;
return(list);
}
void list_free(list_t *list)
{
if(list == NULL) {
return;
}
if(list->data != NULL) {
free(list->data);
list->data = NULL;
}
if(list->next != NULL) {
list_free(list->next);
}
free(list);
return;
}
list_t *list_add(list_t *list, void *data)
{
list_t *ptr, *lp;
ptr = list;
if(ptr == NULL) {
ptr = list_new();
}
lp = list_last(ptr);
if(lp == ptr && lp->data == NULL) {
/* nada */
} else {
lp->next = list_new();
if(lp->next == NULL) {
return(NULL);
}
lp = lp->next;
}
lp->data = data;
return(ptr);
}
int list_count(list_t *list)
{
int i;
list_t *lp;
for(lp = list, i = 0; lp; lp = lp->next, i++);
return(i);
}
static list_t *list_last(list_t *list)
{
list_t *ptr;
for(ptr = list; ptr && ptr->next; ptr = ptr->next);
return(ptr);
}
/* Test for existence of a string in a list_t
*/
int list_is_strin(char *needle, list_t *haystack)
{
list_t *lp;
for(lp = haystack; lp; lp = lp->next) {
if(lp->data && !strcmp(lp->data, needle)) {
return(1);
}
}
return(0);
}
/* Display the content of a list_t struct of strings
*/
void list_display(const char *title, list_t *list)
{
list_t *lp;
int cols, len;
len = strlen(title);
printf("%s ", title);
if(list) {
for(lp = list, cols = len; lp; lp = lp->next) {
int s = strlen((char *)lp->data)+1;
if(s+cols >= maxcols) {
int i;
cols = len;
printf("\n");
for (i = 0; i < len+1; i++) {
printf(" ");
}
}
printf("%s ", (char *)lp->data);
cols += s;
}
printf("\n");
} else {
printf("None\n");
}
}
void PM_LIST_display(const char *title, PM_LIST *list)
{
PM_LIST *lp;
int cols, len;
len = strlen(title);
printf("%s ", title);
if(list) {
for(lp = list, cols = len; lp; lp = alpm_list_next(lp)) {
int s = strlen(alpm_list_getdata(lp))+1;
if(s+cols >= maxcols) {
int i;
cols = len;
printf("\n");
for (i = 0; i < len+1; i++) {
printf(" ");
}
}
printf("%s ", (char *)alpm_list_getdata(lp));
cols += s;
}
printf("\n");
} else {
printf("None\n");
}
}
/* vim: set ts=2 sw=2 noet: */

45
src/pacman/list.h Normal file
View File

@ -0,0 +1,45 @@
/*
* list.h
*
* Copyright (c) 2002-2005 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 _PM_LIST_H
#define _PM_LIST_H
#include <alpm.h>
/* Chained list struct */
typedef struct __list_t {
void *data;
struct __list_t *next;
} list_t;
#define FREELIST(p) do { if(p) { list_free(p); p = NULL; } } while(0)
list_t *list_new();
void list_free(list_t* list);
list_t *list_add(list_t* list, void *data);
int list_count(list_t* list);
int list_is_strin(char *needle, list_t *haystack);
void list_display(const char *title, list_t *list);
void PM_LIST_display(const char *title, PM_LIST *list);
#endif /* _PM_LIST_H */
/* vim: set ts=2 sw=2 noet: */

203
src/pacman/package.c Normal file
View File

@ -0,0 +1,203 @@
/*
* package.c
*
* Copyright (c) 2002-2005 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <alpm.h>
/* pacman */
#include "util.h"
#include "list.h"
#include "package.h"
extern char *pmo_root;
/* Display the content of an installed package
*/
void dump_pkg_full(PM_PKG *pkg, int level)
{
char *date;
if(pkg == NULL) {
return;
}
printf("Name : %s\n", (char *)alpm_pkg_getinfo(pkg, PM_PKG_NAME));
printf("Version : %s\n", (char *)alpm_pkg_getinfo(pkg, PM_PKG_VERSION));
PM_LIST_display("Groups :", alpm_pkg_getinfo(pkg, PM_PKG_GROUPS));
printf("Packager : %s\n", (char *)alpm_pkg_getinfo(pkg, PM_PKG_PACKAGER));
printf("URL : %s\n", (char *)alpm_pkg_getinfo(pkg, PM_PKG_URL));
printf("License : %s\n", (char *)alpm_pkg_getinfo(pkg, PM_PKG_LICENSE));
printf("Architecture : %s\n", (char *)alpm_pkg_getinfo(pkg, PM_PKG_ARCH));
printf("Size : %ld\n", (long int)alpm_pkg_getinfo(pkg, PM_PKG_SIZE));
date = alpm_pkg_getinfo(pkg, PM_PKG_BUILDDATE);
printf("Build Date : %s %s\n", date, strlen(date) ? "UTC" : "");
date = alpm_pkg_getinfo(pkg, PM_PKG_INSTALLDATE);
printf("Install Date : %s %s\n", date, strlen(date) ? "UTC" : "");
printf("Install Script : %s\n", (alpm_pkg_getinfo(pkg, PM_PKG_SCRIPLET) ? "Yes" : "No"));
printf("Reason: : ");
switch((int)alpm_pkg_getinfo(pkg, PM_PKG_REASON)) {
case PM_PKG_REASON_EXPLICIT:
printf("explicitly installed\n");
break;
case PM_PKG_REASON_DEPEND:
printf("installed as a dependency for another package\n");
break;
default:
printf("unknown\n");
break;
}
PM_LIST_display("Provides :", alpm_pkg_getinfo(pkg, PM_PKG_PROVIDES));
PM_LIST_display("Depends On :", alpm_pkg_getinfo(pkg, PM_PKG_DEPENDS));
PM_LIST_display("Required By :", alpm_pkg_getinfo(pkg, PM_PKG_REQUIREDBY));
PM_LIST_display("Conflicts With :", alpm_pkg_getinfo(pkg, PM_PKG_CONFLICTS));
printf("Description : ");
indentprint(alpm_pkg_getinfo(pkg, PM_PKG_DESC), 17);
printf("\n");
/*if(level > 1 && info->backup) {
PM_LIST *i;
fprintf(stdout, "\n");
for(i = alpm_first_entry(info->backup); i; i = alpm_next_entry(i)) {
struct stat buf;
char path[PATH_MAX];
char *md5sum;
char *str = strdup(alpm_get_entry(i));
char *ptr = index(str, '\t');
if(ptr == NULL) {
free(str);
str = NULL;
continue;
}
*ptr = '\0';
ptr++;
snprintf(path, PATH_MAX-1, "%s%s", pmo_root, str);
if(!stat(path, &buf)) {
md5sum = alpm_get_md5sum(path);
if(md5sum == NULL) {
fprintf(stderr, "error calculating md5sum for %s\n", path);
continue;
}
if(strcmp(md5sum, ptr)) {
fprintf(stdout, "MODIFIED\t%s\n", path);
} else {
fprintf(stdout, "NOT MODIFIED\t%s\n", path);
}
} else {
fprintf(stdout, "MISSING\t\t%s\n", path);
}
free(str);
str = NULL;
}
}*/
printf("\n");
}
/* Display the content of a sync package
*/
void dump_pkg_sync(PM_PKG *pkg, char *treename)
{
if(pkg == NULL) {
return;
}
printf("Repository : %s\n", treename);
printf("Name : %s\n", (char *)alpm_pkg_getinfo(pkg, PM_PKG_NAME));
printf("Version : %s\n", (char *)alpm_pkg_getinfo(pkg, PM_PKG_VERSION));
PM_LIST_display("Groups :", alpm_pkg_getinfo(pkg, PM_PKG_GROUPS));
PM_LIST_display("Provides :", alpm_pkg_getinfo(pkg, PM_PKG_PROVIDES));
PM_LIST_display("Depends On :", alpm_pkg_getinfo(pkg, PM_PKG_DEPENDS));
PM_LIST_display("Conflicts With :", alpm_pkg_getinfo(pkg, PM_PKG_CONFLICTS));
PM_LIST_display("Replaces :", alpm_pkg_getinfo(pkg, PM_PKG_REPLACES));
printf("Size (compressed) : %ld\n", (long)alpm_pkg_getinfo(pkg, PM_PKG_SIZE));
printf("Description : ");
indentprint(alpm_pkg_getinfo(pkg, PM_PKG_DESC), 17);
printf("\nMD5 Sum : %s\n", (char *)alpm_pkg_getinfo(pkg, PM_PKG_MD5SUM));
}
void dump_pkg_files(PM_PKG *pkg)
{
char *pkgname;
PM_LIST *i, *pkgfiles;
pkgname = alpm_pkg_getinfo(pkg, PM_PKG_NAME);
pkgfiles = alpm_pkg_getinfo(pkg, PM_PKG_FILES);
for(i = pkgfiles; i; i = alpm_list_next(i)) {
fprintf(stdout, "%s %s\n", (char *)pkgname, (char *)alpm_list_getdata(i));
}
fflush(stdout);
}
int split_pkgname(char *target, char *name, char *version)
{
char tmp[512];
char *p, *q;
if(target == NULL) {
return(-1);
}
/* trim path name (if any) */
if((p = strrchr(target, '/')) == NULL) {
p = target;
} else {
p++;
}
strncpy(tmp, p, 512);
/* trim file extension (if any) */
if((p = strstr(tmp, ".pkg.tar.gz"))) {
*p = 0;
}
p = tmp + strlen(tmp);
for(q = --p; *q && *q != '-'; q--);
if(*q != '-' || q == tmp) {
return(-1);
}
for(p = --q; *p && *p != '-'; p--);
if(*p != '-' || p == tmp) {
return(-1);
}
strncpy(version, p+1, 64);
*p = 0;
strncpy(name, tmp, 256);
return(0);
}
/* vim: set ts=2 sw=2 noet: */

35
src/pacman/package.h Normal file
View File

@ -0,0 +1,35 @@
/*
* package.h
*
* Copyright (c) 2002-2005 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 _PM_PACKAGE_H
#define _PM_PACKAGE_H
void dump_pkg_full(PM_PKG *pkg, int level);
void dump_pkg_sync(PM_PKG *pkg, char *treename);
void dump_pkg_files(PM_PKG *pkg);
int split_pkgname(char *target, char *name, char *version);
#define FREEPKG(p) { alpm_pkg_free(p); p = NULL; }
#endif /* _PM_PACKAGE_H */
/* vim: set ts=2 sw=2 noet: */

688
src/pacman/pacman.c Normal file
View File

@ -0,0 +1,688 @@
/*
* pacman.c
*
* Copyright (c) 2002-2005 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 <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <getopt.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <mcheck.h> /* debug */
#include <alpm.h>
/* pacman */
#include "list.h"
#include "util.h"
#include "download.h"
#include "conf.h"
#include "package.h"
#include "add.h"
#include "remove.h"
#include "upgrade.h"
#include "query.h"
#include "sync.h"
#include "pacman.h"
/* command line options */
char *pmo_root = NULL;
char *pmo_dbpath = NULL;
char *pmo_configfile = NULL;
unsigned short pmo_op = PM_OP_MAIN;
unsigned short pmo_verbose = 0;
unsigned short pmo_version = 0;
unsigned short pmo_help = 0;
unsigned short pmo_upgrade = 0;
unsigned short pmo_nosave = 0;
unsigned short pmo_noconfirm = 0;
unsigned short pmo_d_vertest = 0;
unsigned short pmo_d_resolve = 0;
unsigned short pmo_q_isfile = 0;
unsigned short pmo_q_info = 0;
unsigned short pmo_q_list = 0;
unsigned short pmo_q_orphans = 0;
unsigned short pmo_q_owns = 0;
unsigned short pmo_q_search = 0;
unsigned short pmo_s_upgrade = 0;
unsigned short pmo_s_downloadonly = 0;
unsigned short pmo_s_printuris = 0;
unsigned short pmo_s_sync = 0;
unsigned short pmo_s_search = 0;
unsigned short pmo_s_clean = 0;
unsigned short pmo_group = 0;
unsigned char pmo_flags = 0;
/* configuration file option */
list_t *pmo_holdpkg = NULL;
char *pmo_proxyhost = NULL;
unsigned short pmo_proxyport = 0;
char *pmo_xfercommand = NULL;
unsigned short pmo_nopassiveftp = 0;
PM_DB *db_local;
/* list of (sync_t *) structs for sync locations */
list_t *pmc_syncs = NULL;
/* list of targets specified on command line */
list_t *pm_targets = NULL;
int maxcols = 80;
int neednl = 0; /* for cleaner message output */
int main(int argc, char *argv[])
{
int ret = 0;
char *cenv = NULL;
/* debug */
mtrace();
cenv = getenv("COLUMNS");
if(cenv != NULL) {
maxcols = atoi(cenv);
}
if(argc < 2) {
usage(PM_OP_MAIN, basename(argv[0]));
return(0);
}
/* set signal handlers */
signal(SIGINT, cleanup);
signal(SIGTERM, cleanup);
/* parse the command line */
ret = parseargs(argc, argv);
if(ret != 0) {
exit(ret);
}
if(pmo_root == NULL) {
pmo_root = strdup("/");
}
/* initialize pm library */
if(alpm_initialize(pmo_root) == -1) {
ERR(NL, "failed to initilize alpm library (%s)\n", alpm_strerror(pm_errno));
cleanup(1);
}
/* add a trailing '/' if there isn't one */
if(pmo_root[strlen(pmo_root)-1] != '/') {
char *ptr;
MALLOC(ptr, strlen(pmo_root)+2);
strcpy(ptr, pmo_root);
strcat(ptr, "/");
FREE(pmo_root);
pmo_root = ptr;
}
if(pmo_configfile == NULL) {
pmo_configfile = strdup(PACCONF);
}
if(parseconfig(pmo_configfile) == -1) {
cleanup(1);
}
if(pmo_dbpath == NULL) {
pmo_dbpath = strdup("var/lib/pacman");
}
/* set library parameters */
if(pmo_verbose == 1) {
if(alpm_set_option(PM_OPT_LOGMASK, (long)0xFF) == -1) {
ERR(NL, "failed to set option LOGMASK (%s)\n", alpm_strerror(pm_errno));
cleanup(1);
}
if(alpm_set_option(PM_OPT_LOGCB, (long)cb_log) == -1) {
ERR(NL, "failed to set option LOGCB (%s)\n", alpm_strerror(pm_errno));
cleanup(1);
}
}
if(alpm_set_option(PM_OPT_DBPATH, (long)pmo_dbpath) == -1) {
ERR(NL, "failed to set option DBPATH (%s)\n", alpm_strerror(pm_errno));
cleanup(1);
}
if(pmo_verbose > 1) {
printf("Root : %s\n", pmo_root);
printf("DBPath: %s\n", pmo_dbpath);
list_display("Targets:", pm_targets);
}
/* Opening local database */
if(alpm_db_register("local", &db_local) == -1) {
ERR(NL, "could not register 'local' database (%s)\n", alpm_strerror(pm_errno));
cleanup(1);
}
/* start the requested operation */
switch(pmo_op) {
case PM_OP_ADD: ret = pacman_add(pm_targets); break;
case PM_OP_REMOVE: ret = pacman_remove(pm_targets); break;
case PM_OP_UPGRADE: ret = pacman_upgrade(pm_targets); break;
case PM_OP_QUERY: ret = pacman_query(pm_targets); break;
case PM_OP_SYNC: ret = pacman_sync(pm_targets); break;
case PM_OP_DEPTEST: ret = pacman_deptest(pm_targets); break;
case PM_OP_MAIN: ret = 0; break;
default:
ERR(NL, "no operation specified (use -h for help)\n\n");
ret = 1;
}
cleanup(ret);
/* not reached */
return(0);
}
void cleanup(int signum)
{
list_t *lp;
/* free pm library resources */
if(alpm_release() == -1) {
ERR(NL, "%s\n", alpm_strerror(pm_errno));
}
/* free memory */
for(lp = pmc_syncs; lp; lp = lp->next) {
sync_t *sync = lp->data;
list_t *i;
for(i = sync->servers; i; i = i->next) {
server_t *server = i->data;
FREE(server->protocol);
FREE(server->server);
FREE(server->path);
}
FREELIST(sync->servers);
FREE(sync->treename);
}
FREELIST(pmc_syncs);
FREE(pmo_root);
FREE(pmo_dbpath);
FREE(pmo_configfile);
FREE(pmo_proxyhost);
FREE(pmo_xfercommand);
FREELIST(pm_targets);
/* debug */
muntrace();
fflush(stdout);
exit(signum);
}
/* Callback to handle notifications from the library
*/
void cb_log(unsigned short level, char *msg)
{
char str[8] = "";
switch(level) {
case PM_LOG_DEBUG:
sprintf(str, "DEBUG");
break;
case PM_LOG_ERROR:
sprintf(str, "ERROR");
break;
case PM_LOG_WARNING:
sprintf(str, "WARNING");
break;
case PM_LOG_FLOW1:
sprintf(str, "FLOW1");
break;
case PM_LOG_FLOW2:
sprintf(str, "FLOW2");
break;
case PM_LOG_FUNCTION:
sprintf(str, "FUNCTION");
break;
default:
sprintf(str, "???");
break;
}
if(strlen(str) > 0) {
MSG(NL, "%s: %s\n", str, msg);
}
}
/* Callback to handle transaction events
*/
void cb_trans(unsigned short event, void *data1, void *data2)
{
char str[256] = "";
switch(event) {
case PM_TRANS_CB_DEPS_START:
MSG(NL, "checking dependencies... ");
break;
case PM_TRANS_CB_CONFLICTS_START:
MSG(NL, "checking for file conflicts... ");
break;
case PM_TRANS_CB_DEPS_DONE:
case PM_TRANS_CB_CONFLICTS_DONE:
MSG(CL, "done.\n");
break;
case PM_TRANS_CB_ADD_START:
MSG(NL, "installing %s... ", (char *)alpm_pkg_getinfo(data1, PM_PKG_NAME));
break;
case PM_TRANS_CB_ADD_DONE:
MSG(CL, "done.\n");
snprintf(str, 256, "installed %s (%s)",
(char *)alpm_pkg_getinfo(data1, PM_PKG_NAME),
(char *)alpm_pkg_getinfo(data1, PM_PKG_VERSION));
alpm_logaction(str);
break;
case PM_TRANS_CB_REMOVE_START:
MSG(NL, "removing %s... ", (char *)alpm_pkg_getinfo(data1, PM_PKG_NAME));
break;
case PM_TRANS_CB_REMOVE_DONE:
MSG(CL, "done.\n");
snprintf(str, 256, "removed %s (%s)",
(char *)alpm_pkg_getinfo(data1, PM_PKG_NAME),
(char *)alpm_pkg_getinfo(data1, PM_PKG_VERSION));
alpm_logaction(str);
break;
case PM_TRANS_CB_UPGRADE_START:
MSG(NL, "upgrading %s... ", (char *)alpm_pkg_getinfo(data1, PM_PKG_NAME));
break;
case PM_TRANS_CB_UPGRADE_DONE:
MSG(CL, "done.\n");
snprintf(str, 256, "upgraded %s (%s -> %s)",
(char *)alpm_pkg_getinfo(data1, PM_PKG_NAME),
(char *)alpm_pkg_getinfo(data1, PM_PKG_VERSION),
(char *)alpm_pkg_getinfo(data2, PM_PKG_VERSION));
alpm_logaction(str);
break;
}
}
int pacman_deptest(list_t *targets)
{
PM_LIST *lp, *data;
PM_PKG *dummy;
if(pmo_d_vertest) {
/* ORE
if(targets && targets->data && targets->next && targets->next->data) {
int ret = rpmvercmp(targets->data, targets->next->data);
printf("%d\n", ret);
return(ret);
}*/
return(0);
}
/* we create a transaction to hold a dummy package to be able to use
* pm_trans_prepare() */
/* ORE
trans = alpm_trans_new(PM_TRANS_ADD, 0);
if(trans == NULL) {
FREEPKG(dummy);
ERR(NL, "error: can't allocate %d bytes\n", sizeof(pm_pkginfo_t));
exit(1);
}
dummy = (pm_pkginfo_t *)malloc(sizeof(pm_pkginfo_t));
if(dummy == NULL) {
ERR(NL, "error: can't allocate %d bytes\n", sizeof(pm_pkginfo_t));
exit(1);
}
sprintf(dummy->name, "_dummy_");
sprintf(dummy->version, "1.0-1");
for(i = targets; i; i = i->next) {
if(i->data == NULL) continue;
dummy->depends = list_add(dummy->depends, strdup(i->data)));
}
trans->targets = list_add(trans->targets, strdup(dummy->name));*/
if(alpm_trans_prepare(&data) == -1) {
int ret = 126;
list_t *synctargs = NULL;
switch(pm_errno) {
case PM_ERR_UNSATISFIED_DEPS:
for(lp = alpm_list_first(data); lp; lp = alpm_list_next(lp)) {
pmdepmissing_t *miss = alpm_list_getdata(lp);
if(!pmo_d_resolve) {
MSG(NL, "requires: %s", miss->depend.name);
switch(miss->depend.mod) {
case PM_DEP_EQ: MSG(CL, "=%s", miss->depend.version); break;
case PM_DEP_GE: MSG(CL, ">=%s", miss->depend.version); break;
case PM_DEP_LE: MSG(CL, "<=%s", miss->depend.version); break;
}
MSG(CL, "\n");
}
synctargs = list_add(synctargs, strdup(miss->depend.name));
}
alpm_list_free(data);
break;
case PM_ERR_CONFLICTING_DEPS:
/* we can't auto-resolve conflicts */
for(lp = alpm_list_first(data); lp; lp = alpm_list_next(lp)) {
pmdepmissing_t *miss = alpm_list_getdata(lp);
MSG(NL, "conflict: %s", miss->depend.name);
}
ret = 127;
alpm_list_free(data);
break;
default:
ret = 127;
break;
}
/* attempt to resolve missing dependencies */
/* TODO: handle version comparators (eg, glibc>=2.2.5) */
if(ret == 126 && synctargs != NULL) {
if(!pmo_d_resolve || pacman_sync(synctargs) != 0) {
/* error (or -D not used) */
ret = 127;
}
}
FREELIST(synctargs);
FREEPKG(dummy);
return(ret);
}
FREEPKG(dummy);
return(0);
}
/* Parse command-line arguments for each operation
* argc: argc
* argv: argv
*
* Returns: 0 on success, 1 on error
*/
int parseargs(int argc, char **argv)
{
int opt;
int option_index = 0;
static struct option opts[] =
{
{"add", no_argument, 0, 'A'},
{"remove", no_argument, 0, 'R'},
{"upgrade", no_argument, 0, 'U'},
{"freshen", no_argument, 0, 'F'},
{"query", no_argument, 0, 'Q'},
{"sync", no_argument, 0, 'S'},
{"deptest", no_argument, 0, 'T'},
{"vertest", no_argument, 0, 'Y'},
{"resolve", no_argument, 0, 'D'},
{"root", required_argument, 0, 'r'},
{"dbpath", required_argument, 0, 'b'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{"search", no_argument, 0, 's'},
{"clean", no_argument, 0, 'c'},
{"force", no_argument, 0, 'f'},
{"nodeps", no_argument, 0, 'd'},
{"orphans", no_argument, 0, 'e'},
{"nosave", no_argument, 0, 'n'},
{"owns", no_argument, 0, 'o'},
{"list", no_argument, 0, 'l'},
{"file", no_argument, 0, 'p'},
{"info", no_argument, 0, 'i'},
{"sysupgrade", no_argument, 0, 'u'},
{"downloadonly", no_argument, 0, 'w'},
{"refresh", no_argument, 0, 'y'},
{"dbonly", no_argument, 0, 'k'},
{"cascade", no_argument, 0, 'c'},
{"recursive", no_argument, 0, 's'},
{"groups", no_argument, 0, 'g'},
{"noconfirm", no_argument, 0, 1000},
{"config", required_argument, 0, 1001},
{0, 0, 0, 0}
};
char root[256];
while((opt = getopt_long(argc, argv, "ARUFQSTDYr:b:vkhscVfnoldepiuwyg", opts, &option_index))) {
if(opt < 0) {
break;
}
switch(opt) {
case 0: break;
case 1000: pmo_noconfirm = 1; break;
case 1001: pmo_configfile = strndup(optarg, PATH_MAX); break;
case 'A': pmo_op = (pmo_op != PM_OP_MAIN ? 0 : PM_OP_ADD); break;
case 'R': pmo_op = (pmo_op != PM_OP_MAIN ? 0 : PM_OP_REMOVE); break;
case 'U': pmo_op = (pmo_op != PM_OP_MAIN ? 0 : PM_OP_UPGRADE); break;
case 'F': pmo_op = (pmo_op != PM_OP_MAIN ? 0 : PM_OP_UPGRADE); pmo_flags |= PM_TRANS_FLAG_FRESHEN; break;
case 'Q': pmo_op = (pmo_op != PM_OP_MAIN ? 0 : PM_OP_QUERY); break;
case 'S': pmo_op = (pmo_op != PM_OP_MAIN ? 0 : PM_OP_SYNC); break;
case 'T': pmo_op = (pmo_op != PM_OP_MAIN ? 0 : PM_OP_DEPTEST); break;
case 'Y': pmo_op = (pmo_op != PM_OP_MAIN ? 0 : PM_OP_DEPTEST); pmo_d_vertest = 1; break;
case 'D': pmo_op = (pmo_op != PM_OP_MAIN ? 0 : PM_OP_DEPTEST); pmo_d_resolve = 1; break;
case 'h': pmo_help = 1; break;
case 'V': pmo_version = 1; break;
case 'b': pmo_dbpath = strdup(optarg); break;
case 'c': pmo_s_clean++; pmo_flags |= PM_TRANS_FLAG_CASCADE; break;
case 'd': pmo_flags |= PM_TRANS_FLAG_NODEPS; break;
case 'e': pmo_q_orphans = 1; break;
case 'f': pmo_flags |= PM_TRANS_FLAG_FORCE; break;
case 'g': pmo_group = 1; break;
case 'i': pmo_q_info++; break;
case 'k': pmo_flags |= PM_TRANS_FLAG_DBONLY; break;
case 'l': pmo_q_list = 1; break;
case 'n': pmo_flags |= PM_TRANS_FLAG_NOSAVE; break;
case 'p': pmo_q_isfile = 1; break;
case 'o': pmo_q_owns = 1; break;
case 'r':
if(realpath(optarg, root) == NULL) {
perror("bad root path");
return(1);
}
pmo_root = strdup(root);
break;
case 's': pmo_s_search = 1; pmo_q_search = 1; pmo_flags |= PM_TRANS_FLAG_RECURSE; break;
case 'u': pmo_s_upgrade = 1; break;
case 'v': pmo_verbose++; break;
case 'w': pmo_s_downloadonly = 1; break;
case 'y': pmo_s_sync = 1; break;
case '?': return(1);
default: return(1);
}
}
if(pmo_op == 0) {
ERR(NL, "only one operation may be used at a time\n\n");
return(1);
}
if(pmo_help) {
usage(pmo_op, basename(argv[0]));
return(2);
}
if(pmo_version) {
version();
return(2);
}
while(optind < argc) {
/* add the target to our target array */
char *s = strdup(argv[optind]);
pm_targets = list_add(pm_targets, s);
optind++;
}
return(0);
}
/* 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_OP_MAIN) {
printf("usage: %s {-h --help}\n", myname);
printf(" %s {-V --version}\n", myname);
printf(" %s {-A --add} [options] <file>\n", myname);
printf(" %s {-R --remove} [options] <package>\n", myname);
printf(" %s {-U --upgrade} [options] <file>\n", myname);
printf(" %s {-F --freshen} [options] <file>\n", myname);
printf(" %s {-Q --query} [options] [package]\n", myname);
printf(" %s {-S --sync} [options] [package]\n", myname);
printf("\nuse '%s --help' with other options for more syntax\n\n", myname);
} else {
if(op == PM_OP_ADD) {
printf("usage: %s {-A --add} [options] <file>\n", myname);
printf("options:\n");
printf(" -d, --nodeps skip dependency checks\n");
printf(" -f, --force force install, overwrite conflicting files\n");
} else if(op == PM_OP_REMOVE) {
printf("usage: %s {-R --remove} [options] <package>\n", myname);
printf("options:\n");
printf(" -c, --cascade remove packages and all packages that depend on them\n");
printf(" -d, --nodeps skip dependency checks\n");
printf(" -k, --dbonly only remove database entry, do not remove files\n");
printf(" -n, --nosave remove configuration files as well\n");
printf(" -s, --recursive remove dependencies also (that won't break packages)\n");
} else if(op == PM_OP_UPGRADE) {
if(pmo_flags & PM_TRANS_FLAG_FRESHEN) {
printf("usage: %s {-F --freshen} [options] <file>\n", myname);
} else {
printf("usage: %s {-U --upgrade} [options] <file>\n", myname);
}
printf("options:\n");
printf(" -d, --nodeps skip dependency checks\n");
printf(" -f, --force force install, overwrite conflicting files\n");
} else if(op == PM_OP_QUERY) {
printf("usage: %s {-Q --query} [options] [package]\n", myname);
printf("options:\n");
printf(" -e, --orphans list all packages that were explicitly installed\n");
printf(" and are not required by any other packages\n");
printf(" -g, --groups view all members of a package group\n");
printf(" -i, --info view package information\n");
printf(" -l, --list list the contents of the queried package\n");
printf(" -o, --owns <file> query the package that owns <file>\n");
printf(" -p, --file pacman will query the package file [package] instead of\n");
printf(" looking in the database\n");
printf(" -s, --search search locally-installed packages for matching strings\n");
} else if(op == PM_OP_SYNC) {
printf("usage: %s {-S --sync} [options] [package]\n", myname);
printf("options:\n");
printf(" -c, --clean remove old packages from cache directory (use -cc for all)\n");
printf(" -d, --nodeps skip dependency checks\n");
printf(" -f, --force force install, overwrite conflicting files\n");
printf(" -g, --groups view all members of a package group\n");
printf(" -s, --search search remote repositories for matching strings\n");
printf(" -u, --sysupgrade upgrade all packages that are out of date\n");
printf(" -w, --downloadonly download packages but do not install/upgrade anything\n");
printf(" -y, --refresh download fresh package databases from the server\n");
}
printf(" --config <path> set an alternate configuration file\n");
printf(" --noconfirm do not ask for anything confirmation\n");
printf(" -v, --verbose be verbose\n");
printf(" -r, --root <path> set an alternate installation root\n");
printf(" -b, --dbpath <path> set an alternate database location\n");
}
}
/* Version
*/
void version()
{
printf("\n");
printf(" .--. Pacman v%s\n", ALPM_VERSION);
printf("/ _.-' .-. .-. .-. Copyright (C) 2002-2003 Judd Vinet <jvinet@zeroflux.org>\n");
printf("\\ '-. '-' '-' '-' \n");
printf(" '--' This program may be freely redistributed under\n");
printf(" the terms of the GNU General Public License\n\n");
}
/*
* Misc functions
*/
/* Condense a list of strings into one long (space-delimited) string
*/
char *buildstring(list_t *strlist)
{
char *str;
int size = 1;
list_t *lp;
for(lp = strlist; lp; lp = lp->next) {
size += strlen(lp->data) + 1;
}
str = (char *)malloc(size);
if(str == NULL) {
ERR(NL, "failed to allocated %d bytes\n", size);
}
str[0] = '\0';
for(lp = strlist; lp; lp = lp->next) {
strcat(str, lp->data);
strcat(str, " ");
}
/* shave off the last space */
str[strlen(str)-1] = '\0';
return(str);
}
/* Check verbosity option and, if set, print the
* string to stdout
*/
void vprint(char *fmt, ...)
{
va_list args;
if(pmo_verbose > 1) {
if(neednl == 1) {
fprintf(stdout, "\n");
neednl = 0;
}
va_start(args, fmt);
pm_fprintf(stdout, NL, fmt, args);
va_end(args);
}
}
void pm_fprintf(FILE *file, unsigned short line, char *fmt, ...)
{
va_list args;
char str[256];
if(neednl == 1 && line == NL) {
fprintf(stdout, "\n");
neednl = 0;
}
va_start(args, fmt);
vsnprintf(str, 256, fmt, args);
va_end(args);
fprintf(file, str);
fflush(file);
neednl = (str[strlen(str)-1] == 10) ? 0 : 1;
}
/* vim: set ts=2 sw=2 noet: */

75
src/pacman/pacman.h Normal file
View File

@ -0,0 +1,75 @@
/*
* pacman.h
*
* Copyright (c) 2002-2005 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 _PM_PACMAN_H
#define _PM_PACMAN_H
#ifndef PACCONF
#define PACCONF "/etc/pacman.conf"
#endif
#ifndef CACHEDIR
#define CACHEDIR "var/cache/pacman/pkg"
#endif
/* Operations */
#define PM_OP_MAIN 1
#define PM_OP_ADD 2
#define PM_OP_REMOVE 3
#define PM_OP_UPGRADE 4
#define PM_OP_QUERY 5
#define PM_OP_SYNC 6
#define PM_OP_DEPTEST 7
#define MSG(line, fmt, args...) pm_fprintf(stdout, line, fmt, ##args)
#define ERR(line, fmt, args...) do { \
pm_fprintf(stderr, line, "error: "); \
pm_fprintf(stderr, CL, fmt, ##args); \
} while(0)
#define DBG(line, fmt, args...) do { \
char str[256]; \
snprintf(str, 256, fmt, ##args); \
cb_log(PM_LOG_DEBUG, str); \
} while(0)
enum {
NL, /* new line */
CL /* current line */
};
/* callback to handle messages/notifications from pacman library */
void cb_log(unsigned short level, char *msg);
/* callback to handle messages/notifications from pacman transactions */
void cb_trans(unsigned short event, void *data1, void *data2);
void cleanup(int signum);
int pacman_deptest(list_t *targets);
int parseargs(int argc, char **argv);
void usage(int op, char *myname);
void version();
char *buildstring(list_t *strlist);
void vprint(char *fmt, ...);
void pm_fprintf(FILE *file, unsigned short line, char *fmt, ...);
#endif /* _PM_PACMAN_H */
/* vim: set ts=2 sw=2 noet: */

247
src/pacman/query.c Normal file
View File

@ -0,0 +1,247 @@
/*
* query.c
*
* Copyright (c) 2002-2005 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 <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <sys/stat.h>
#include <alpm.h>
/* pacman */
#include "list.h"
#include "package.h"
#include "db.h"
#include "query.h"
#include "pacman.h"
extern char *pmo_root;
extern unsigned short pmo_q_isfile;
extern unsigned short pmo_q_info;
extern unsigned short pmo_q_list;
extern unsigned short pmo_q_orphans;
extern unsigned short pmo_q_owns;
extern unsigned short pmo_q_search;
extern unsigned short pmo_group;
extern PM_DB *db_local;
static int query_fileowner(PM_DB *db, char *filename)
{
struct stat buf;
int gotcha = 0;
char rpath[PATH_MAX];
PM_LIST *lp;
if(db == NULL) {
return(0);
}
if(filename == NULL || strlen(filename) == 0) {
fprintf(stderr, "error: no file was specified for --owns\n");
return(1);
}
if(stat(filename, &buf) == -1 || S_ISDIR(buf.st_mode) || realpath(filename, rpath) == NULL) {
fprintf(stderr, "error: %s is not a file.\n", filename);
return(1);
}
for(lp = alpm_db_getpkgcache(db); lp && !gotcha; lp = alpm_list_next(lp)) {
PM_PKG *info;
char *pkgname;
PM_LIST *i;
pkgname = alpm_pkg_getinfo(alpm_list_getdata(lp), PM_PKG_NAME);
info = alpm_db_readpkg(db, pkgname);
if(info == NULL) {
fprintf(stderr, "error: package %s not found\n", pkgname);
return(1);
}
for(i = alpm_pkg_getinfo(info, PM_PKG_FILES); i && !gotcha; i = alpm_list_next(i)) {
char path[PATH_MAX];
snprintf(path, PATH_MAX, "%s%s", pmo_root, (char *)alpm_list_getdata(i));
if(!strcmp(path, rpath)) {
printf("%s is owned by %s %s\n", filename, pkgname,
(char *)alpm_pkg_getinfo(info, PM_PKG_VERSION));
gotcha = 1;
break;
}
}
}
if(!gotcha) {
fprintf(stderr, "No package owns %s\n", filename);
return(1);
}
return(0);
}
int pacman_query(list_t *targets)
{
PM_PKG *info = NULL;
list_t *targ;
char *package = NULL;
int done = 0;
if(pmo_q_search) {
for(targ = targets; targ; targ = targ->next) {
db_search(db_local, "local", targ->data);
}
return(0);
}
for(targ = targets; !done; targ = (targ ? targ->next : NULL)) {
if(targets == NULL) {
done = 1;
} else {
if(targ->next == NULL) {
done = 1;
}
package = targ->data;
}
/* looking for groups */
if(pmo_group) {
PM_LIST *lp;
if(targets == NULL) {
for(lp = alpm_db_getgrpcache(db_local); lp; lp = alpm_list_next(lp)) {
PM_GRP *grp = alpm_list_getdata(lp);
PM_LIST *i, *pkgnames;
char *grpname;
grpname = alpm_grp_getinfo(grp, PM_GRP_NAME);
pkgnames = alpm_grp_getinfo(grp, PM_GRP_PKGNAMES);
for(i = pkgnames; i; i = alpm_list_next(i)) {
MSG(NL, "%s %s\n", grpname, (char *)alpm_list_getdata(i));
}
}
} else {
PM_GRP *grp = alpm_db_readgrp(db_local, package);
if(grp) {
PM_LIST *i, *pkgnames = alpm_grp_getinfo(grp, PM_GRP_PKGNAMES);
for(i = pkgnames; i; i = alpm_list_next(i)) {
MSG(NL, "%s %s\n", package, (char *)alpm_list_getdata(i));
}
} else {
ERR(NL, "group \"%s\" was not found\n", package);
return(2);
}
}
continue;
}
/* output info for a .tar.gz package */
if(pmo_q_isfile) {
if(package == NULL) {
ERR(NL, "no package file was specified for --file\n");
return(1);
}
if(alpm_pkg_load(package, &info) == -1) {
ERR(NL, "failed to load package '%s' (%s)\n", package, alpm_strerror(pm_errno));
return(1);
}
if(pmo_q_info) {
dump_pkg_full(info, 0);
MSG(NL, "\n");
}
if(pmo_q_list) {
dump_pkg_files(info);
}
if(!pmo_q_info && !pmo_q_list) {
MSG(NL, "%s %s\n", (char *)alpm_pkg_getinfo(info, PM_PKG_NAME),
(char *)alpm_pkg_getinfo(info, PM_PKG_VERSION));
}
FREEPKG(info);
continue;
}
/* determine the owner of a file */
if(pmo_q_owns) {
return(query_fileowner(db_local, package));
}
/* find packages in the db */
if(package == NULL) {
PM_LIST *lp;
/* no target */
for(lp = alpm_db_getpkgcache(db_local); lp; lp = alpm_list_next(lp)) {
PM_PKG *tmpp = alpm_list_getdata(lp);
char *pkgname, *pkgver;
pkgname = alpm_pkg_getinfo(tmpp, PM_PKG_NAME);
pkgver = alpm_pkg_getinfo(tmpp, PM_PKG_VERSION);
if(pmo_q_list || pmo_q_orphans) {
info = alpm_db_readpkg(db_local, pkgname);
if(info == NULL) {
/* something weird happened */
ERR(NL, "package \"%s\" not found\n", pkgname);
return(1);
}
if(pmo_q_list) {
dump_pkg_files(info);
}
if(pmo_q_orphans) {
if(alpm_pkg_getinfo(info, PM_PKG_REQUIREDBY) == NULL
&& alpm_pkg_getinfo(info, PM_PKG_REASON) == PM_PKG_REASON_EXPLICIT) {
MSG(NL, "%s %s\n", pkgname, pkgver);
}
}
} else {
MSG(NL, "%s %s\n", pkgname, pkgver);
}
}
} else {
char *pkgname, *pkgver;
info = alpm_db_readpkg(db_local, package);
if(info == NULL) {
ERR(NL, "package \"%s\" not found\n", package);
return(2);
}
/* find a target */
if(pmo_q_info || pmo_q_list) {
if(pmo_q_info) {
dump_pkg_full(info, pmo_q_info);
}
if(pmo_q_list) {
dump_pkg_files(info);
}
} else if(pmo_q_orphans) {
if(alpm_pkg_getinfo(info, PM_PKG_REQUIREDBY) == NULL) {
MSG(NL, "%s %s\n", pkgname, pkgver);
}
} else {
pkgname = alpm_pkg_getinfo(info, PM_PKG_NAME);
pkgver = alpm_pkg_getinfo(info, PM_PKG_VERSION);
MSG(NL, "%s %s\n", pkgname, pkgver);
}
}
}
return(0);
}
/* vim: set ts=2 sw=2 noet: */

28
src/pacman/query.h Normal file
View File

@ -0,0 +1,28 @@
/*
* query.h
*
* Copyright (c) 2002-2005 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 _PM_QUERY_H
#define _PM_QUERY_H
int pacman_query(list_t *targets);
#endif /* _PM_QUERY_H */
/* vim: set ts=2 sw=2 noet: */

137
src/pacman/remove.c Normal file
View File

@ -0,0 +1,137 @@
/*
* remove.c
*
* Copyright (c) 2002-2005 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <alpm.h>
/* pacman */
#include "util.h"
#include "list.h"
#include "pacman.h"
extern unsigned char pmo_flags;
extern PM_DB *db_local;
int pacman_remove(list_t *targets)
{
PM_LIST *data;
list_t *i;
list_t *finaltargs = NULL;
if(targets == NULL) {
return(0);
}
/* If the target is a group, ask if its packages should be removed
* (the library can't remove groups for now)
*/
for(i = targets; i; i = i->next) {
PM_GRP *grp;
grp = alpm_db_readgrp(db_local, i->data);
if(grp) {
PM_LIST *lp, *pkgnames;
int all;
pkgnames = alpm_grp_getinfo(grp, PM_GRP_PKGNAMES);
MSG(NL, ":: group %s:\n", alpm_grp_getinfo(grp, PM_GRP_NAME));
PM_LIST_display(" ", pkgnames);
all = yesno(" Remove whole content? [Y/n] ");
for(lp = alpm_list_first(pkgnames); lp; lp = alpm_list_next(lp)) {
if(all || yesno(":: Remove %s from group %s? [Y/n] ", (char *)alpm_list_getdata(lp), i->data)) {
finaltargs = list_add(finaltargs, strdup(alpm_list_getdata(lp)));
}
}
} else {
/* not a group, so add it to the final targets */
finaltargs = list_add(finaltargs, strdup(i->data));
}
}
/* Step 1: create a new transaction
*/
if(alpm_trans_init(PM_TRANS_TYPE_REMOVE, pmo_flags, cb_trans) == -1) {
ERR(NL, "failed to init transaction (%s)\n", alpm_strerror(pm_errno));
goto error;
}
/* and add targets to it */
for(i = finaltargs; i; i = i->next) {
if(alpm_trans_addtarget(i->data) == -1) {
ERR(NL, "failed to add target '%s' (%s)\n", (char *)i->data, alpm_strerror(pm_errno));
goto error;
}
}
/* Step 2: prepare the transaction based on its type, targets and flags
*/
if(alpm_trans_prepare(&data) == -1) {
PM_LIST *i;
ERR(NL, "failed to prepare transaction (%s)\n", alpm_strerror(pm_errno));
switch(pm_errno) {
case PM_ERR_UNSATISFIED_DEPS:
for(i = alpm_list_first(data); i; i = alpm_list_next(i)) {
pmdepmissing_t *miss = alpm_list_getdata(i);
MSG(NL, " %s: is required by %s\n", miss->target, miss->depend.name);
}
alpm_list_free(data);
break;
default:
ERR(NL, "%s\n", alpm_strerror(pm_errno));
}
goto error;
}
/* Warn user in case of dangerous operation
*/
if(pmo_flags & PM_TRANS_FLAG_RECURSE || pmo_flags & PM_TRANS_FLAG_CASCADE) {
/* list transaction targets */
PM_LIST_display("\nTargets:", alpm_trans_getinfo(PM_TRANS_TARGETS));
/* get confirmation */
if(yesno("\nDo you want to remove these packages? [Y/n] ") == 0) {
goto error;
}
MSG(NL, "\n");
}
/* Step 3: actually perform the removal
*/
if(alpm_trans_commit() == -1) {
ERR(NL, "failed to commit transaction (%s)\n", alpm_strerror(pm_errno));
goto error;
}
/* Step 4: cleanup */
FREELIST(finaltargs);
return(0);
error:
FREELIST(finaltargs);
alpm_trans_release();
return(1);
}
/* vim: set ts=2 sw=2 noet: */

28
src/pacman/remove.h Normal file
View File

@ -0,0 +1,28 @@
/*
* remove.h
*
* Copyright (c) 2002-2005 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 _PM_REMOVE_H
#define _PM_REMOVE_H
int pacman_remove(list_t *targets);
#endif /* _PM_REMOVE_H */
/* vim: set ts=2 sw=2 noet: */

806
src/pacman/sync.c Normal file
View File

@ -0,0 +1,806 @@
/*
* sync.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <alpm.h>
/* pacman */
#include "util.h"
#include "download.h"
#include "list.h"
#include "package.h"
#include "db.h"
#include "sync.h"
#include "pacman.h"
extern char *pmo_root;
extern char *pmo_dbpath;
extern unsigned short pmo_noconfirm;
extern unsigned short pmo_d_resolve;
extern unsigned short pmo_q_info;
extern unsigned short pmo_q_list;
extern unsigned short pmo_s_upgrade;
extern unsigned short pmo_s_downloadonly;
extern unsigned short pmo_s_printuris;
extern unsigned short pmo_s_sync;
extern unsigned short pmo_s_search;
extern unsigned short pmo_s_clean;
extern unsigned short pmo_group;
extern unsigned char pmo_flags;
extern PM_DB *db_local;
extern list_t *pmc_syncs;
extern int maxcols;
static int sync_cleancache(int level)
{
if(level == 1) {
/* incomplete cleanup: we keep latest packages and partial downloads */
DIR *dir;
struct dirent *ent;
list_t *cache = NULL;
list_t *clean = NULL;
list_t *i, *j;
printf("removing old packages from cache... ");
dir = opendir("/var/cache/pacman/pkg");
if(dir == NULL) {
fprintf(stderr, "error: could not access cache directory\n");
return(1);
}
rewinddir(dir);
while((ent = readdir(dir)) != NULL) {
if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
continue;
}
cache = list_add(cache, strdup(ent->d_name));
}
closedir(dir);
for(i = cache; i; i = i->next) {
char *str = i->data;
char name[256], version[64];
if(strstr(str, ".pkg.tar.gz") == NULL) {
clean = list_add(clean, strdup(str));
continue;
}
/* we keep partially downloaded files */
if(strstr(str, ".pkg.tar.gz.part")) {
continue;
}
if(split_pkgname(str, name, version) != 0) {
clean = list_add(clean, strdup(str));
continue;
}
for(j = i->next; j; j = j->next) {
char *s = j->data;
char n[256], v[64];
if(strstr(s, ".pkg.tar.gz") == NULL) {
continue;
}
if(strstr(s, ".pkg.tar.gz.part")) {
continue;
}
if(split_pkgname(s, n, v) != 0) {
continue;
}
if(!strcmp(name, n)) {
char *ptr = (alpm_pkg_vercmp(version, v) < 0) ? str : s;
if(!list_is_strin(ptr, clean)) {
clean = list_add(clean, strdup(ptr));
}
}
}
}
FREELIST(cache);
for(i = clean; i; i = i->next) {
char path[PATH_MAX];
snprintf(path, PATH_MAX, "%s%s/%s", pmo_root, CACHEDIR, (char *)i->data);
unlink(path);
}
FREELIST(clean);
} else {
/* ORE
// full cleanup
mode_t oldmask;
char path[PATH_MAX];
snprintf(path, PATH_MAX, "%s%s", pmo_root, CACHEDIR);
printf("removing all packages from cache... ");
if(rmrf(path)) {
fprintf(stderr, "error: could not remove cache directory\n");
return(1);
}
oldmask = umask(0000);
if(makepath(path)) {
fprintf(stderr, "error: could not create new cache directory\n");
return(1);
}
umask(oldmask);*/
}
printf("done.\n");
return(0);
}
static int sync_synctree(list_t *syncs)
{
char path[PATH_MAX];
mode_t oldmask;
list_t *files = NULL;
list_t *i;
int success = 0;
for(i = syncs; i; i = i->next) {
sync_t *sync = (sync_t *)i->data;
/* build a one-element list */
snprintf(path, PATH_MAX, "%s.db.tar.gz", sync->treename);
files = list_add(files, strdup(path));
success = 1;
if(downloadfiles(sync->servers, pmo_dbpath, files)) {
fprintf(stderr, "failed to synchronize %s\n", sync->treename);
success = 0;
}
FREELIST(files);
snprintf(path, PATH_MAX, "%s/%s.db.tar.gz", pmo_dbpath, sync->treename);
if(success) {
char ldir[PATH_MAX];
snprintf(ldir, PATH_MAX, "%s/%s", pmo_dbpath, sync->treename);
/* remove the old dir */
vprint("removing %s (if it exists)\n", ldir);
rmrf(ldir);
/* make the new dir */
oldmask = umask(0000);
mkdir(ldir, 0755);
umask(oldmask);
/* uncompress the sync database */
vprint("Unpacking %s...\n", path);
if(unpack(path, ldir, NULL)) {
return(1);
}
}
/* remove the .tar.gz */
unlink(path);
}
return(!success);
}
static int sync_search(list_t *syncs, list_t *targets)
{
list_t *i;
for(i = syncs; i; i = i->next) {
sync_t *sync = i->data;
if(targets) {
list_t *j;
for(j = targets; j; j = j->next) {
db_search(sync->db, sync->treename, j->data);
}
} else {
PM_LIST *lp;
for(lp = alpm_db_getpkgcache(sync->db); lp; lp = alpm_list_next(lp)) {
PM_PKG *pkg = alpm_list_getdata(lp);
printf("%s/%s %s\n ", sync->treename, (char *)alpm_pkg_getinfo(pkg, PM_PKG_NAME), (char *)alpm_pkg_getinfo(pkg, PM_PKG_VERSION));
indentprint(alpm_pkg_getinfo(pkg, PM_PKG_DESC), 4);
printf("\n");
}
}
}
return(0);
}
static int sync_group(list_t *syncs, list_t *targets)
{
list_t *i, *j;
if(targets) {
for(i = targets; i; i = i->next) {
for(j = syncs; j; j = j->next) {
sync_t *sync = j->data;
PM_GRP *grp = alpm_db_readgrp(sync->db, i->data);
if(grp) {
printf("%s/%s\n", sync->treename, (char *)alpm_grp_getinfo(grp, PM_GRP_NAME));
PM_LIST_display(" ", alpm_grp_getinfo(grp, PM_GRP_PKGNAMES));
}
}
}
} else {
for(j = syncs; j; j = j->next) {
sync_t *sync = j->data;
PM_LIST *lp;
for(lp = alpm_db_getpkgcache(sync->db); lp; lp = alpm_list_next(lp)) {
PM_GRP *grp = alpm_list_getdata(lp);
printf("%s/%s\n", (char *)sync->treename, (char *)alpm_grp_getinfo(grp, PM_GRP_NAME));
PM_LIST_display(" ", alpm_grp_getinfo(grp, PM_GRP_PKGNAMES));
}
}
}
return(0);
}
static int sync_info(list_t *syncs, list_t *targets)
{
list_t *i, *j;
if(targets) {
for(i = targets; i; i = i->next) {
int found = 0;
for(j = syncs; j && !found; j = j->next) {
sync_t *sync = j->data;
PM_LIST *lp;
for(lp = alpm_db_getpkgcache(sync->db); !found && lp; lp = alpm_list_next(lp)) {
PM_PKG *pkg = alpm_list_getdata(lp);
if(!strcmp(alpm_pkg_getinfo(pkg, PM_PKG_NAME), i->data)) {
dump_pkg_sync(pkg, sync->treename);
printf("\n");
found = 1;
}
}
}
if(!found) {
fprintf(stderr, "Package \"%s\" was not found.\n", (char *)i->data);
break;
}
}
} else {
for(j = syncs; j; j = j->next) {
sync_t *sync = j->data;
PM_LIST *lp;
for(lp = alpm_db_getpkgcache(sync->db); lp; lp = alpm_list_next(lp)) {
dump_pkg_sync(alpm_list_getdata(lp), sync->treename);
printf("\n");
}
}
}
return(0);
}
static int sync_list(list_t *syncs, list_t *targets)
{
list_t *i, *treenames = NULL;
if(targets) {
for(i = targets; i; i = i->next) {
list_t *j;
sync_t *sync = NULL;
for(j = syncs; j; j = j->next) {
sync_t *s = j->data;
if(strcmp(i->data, s->treename) == 0) {
MALLOC(sync, sizeof(sync_t));
sync->treename = i->data;
sync->db = s->db;
}
}
if(sync == NULL) {
fprintf(stderr, "Repository \"%s\" was not found.\n\n", (char *)i->data);
list_free(treenames);
return(1);
}
treenames = list_add(treenames, sync);
}
} else {
treenames = syncs;
}
for(i = treenames; i; i = i->next) {
PM_LIST *lp;
sync_t *sync = i->data;
for(lp = alpm_db_getpkgcache(sync->db); lp; lp = alpm_list_next(lp)) {
PM_PKG *pkg = alpm_list_getdata(lp);
printf("%s %s %s\n", (char *)sync->treename, (char *)alpm_pkg_getinfo(pkg, PM_PKG_NAME), (char *)alpm_pkg_getinfo(pkg, PM_PKG_VERSION));
}
}
if(targets) {
list_free(treenames);
}
return(0);
}
int pacman_sync(list_t *targets)
{
int allgood = 1, confirm = 0;
int retval = 0;
list_t *final = NULL;
list_t *i, *j;
PM_LIST *lp, *data;
char ldir[PATH_MAX];
int varcache = 1;
int done = 0;
int count = 0;
sync_t *current = NULL;
list_t *processed = NULL;
list_t *files = NULL;
if(pmc_syncs == NULL || !list_count(pmc_syncs)) {
ERR(NL, "error: no usable package repositories configured.");
return(1);
}
if(pmo_s_clean) {
return(sync_cleancache(pmo_s_clean));
}
if(pmo_s_sync) {
/* grab a fresh package list */
MSG(NL, ":: Synchronizing package databases...\n");
alpm_logaction("synchronizing package lists");
sync_synctree(pmc_syncs);
}
/* open the database(s) */
for(i = pmc_syncs; i; i = i->next) {
sync_t *sync = i->data;
if(alpm_db_register(sync->treename, &sync->db) == -1) {
ERR(NL, "%s\n", alpm_strerror(pm_errno));
return(1);
}
}
if(pmo_s_search) {
return(sync_search(pmc_syncs, targets));
}
if(pmo_group) {
return(sync_group(pmc_syncs, targets));
}
if(pmo_q_info) {
return(sync_info(pmc_syncs, targets));
}
if(pmo_q_list) {
return(sync_list(pmc_syncs, targets));
}
if(pmo_s_upgrade) {
/* ORE
alpm_logaction(NULL, "starting full system upgrade");*/
if(alpm_sync_sysupgrade(&data) == -1) {
if(pm_errno == PM_ERR_UNRESOLVABLE_DEPS) {
ERR(NL, "cannot resolve dependencies\n");
for(lp = alpm_list_first(data); lp; lp = alpm_list_next(lp)) {
pmdepmissing_t *miss = alpm_list_getdata(lp);
ERR(NL, " %s: \"%s\" is not in the package set\n", miss->target, miss->depend.name);
}
alpm_list_free(data);
} else {
ERR(NL, "%s\n", alpm_strerror(pm_errno));
}
return(1);
}
/* check if pacman itself is one of the packages to upgrade. If so, we
* we should upgrade ourselves first and then re-exec as the new version.
*
* this can prevent some of the "syntax error" problems users can have
* when sysupgrade'ing with an older version of pacman.
*/
for(lp = alpm_list_first(data); lp; lp = alpm_list_next(lp)) {
PM_SYNC *sync = alpm_list_getdata(lp);
if(!strcmp("pacman", alpm_pkg_getinfo(alpm_sync_getinfo(sync, PM_SYNC_SYNCPKG), PM_PKG_NAME))) {
ERR(NL, "\n:: pacman has detected a newer version of the \"pacman\" package.\n");
ERR(NL, ":: It is recommended that you allow pacman to upgrade itself\n");
ERR(NL, ":: first, then you can re-run the operation with the newer version.\n");
ERR(NL, "::\n");
if(yesno(":: Upgrade pacman first? [Y/n] ")) {
alpm_list_free(data);
data = NULL;
}
}
}
for(lp = alpm_list_first(data); lp; lp = alpm_list_next(lp)) {
PM_SYNC *sync = alpm_list_getdata(lp);
PM_PKG *lpkg, *spkg;
char *spkgname, *spkgver, *lpkgname, *lpkgver;
lpkg = alpm_sync_getinfo(sync, PM_SYNC_LOCALPKG);
lpkgname = alpm_pkg_getinfo(lpkg, PM_PKG_NAME);
lpkgver = alpm_pkg_getinfo(lpkg, PM_PKG_VERSION);
spkg = alpm_sync_getinfo(sync, PM_SYNC_SYNCPKG);
spkgname = alpm_pkg_getinfo(spkg, PM_PKG_NAME);
spkgver = alpm_pkg_getinfo(spkg, PM_PKG_VERSION);
switch((int)alpm_sync_getinfo(sync, PM_SYNC_TYPE)) {
case PM_SYSUPG_REPLACE:
if(yesno(":: Replace %s with %s from \"%s\"? [Y/n] ", lpkgname, spkgname, NULL/*dbs->db->treename*/)) {
DBG("adding '%s-%s' to replaces candidates\n", spkgname, spkgver);
final = list_add(final, spkg);
}
break;
case PM_SYSUPG_UPGRADE:
DBG("Upgrade %s (%s => %s)\n", lpkgname, lpkgver, spkgver);
final = list_add(final, spkg);
break;
default:
break;
}
}
alpm_list_free(data);
} else {
/* process targets */
for(i = targets; i; i = i->next) {
char *treename;
char *targ;
char *targline;
PM_PKG *local = NULL;
targline = strdup((char *)i->data);
targ = index(targline, '/');
if(targ) {
*targ = '\0';
targ++;
treename = targline;
} else {
targ = targline;
treename = NULL;
}
if(treename == NULL) {
for(j = pmc_syncs; j && !local; j = j->next) {
sync_t *sync = j->data;
local = alpm_db_readpkg(sync->db, targ);
}
} else {
for(j = pmc_syncs; j && !local; j = j->next) {
sync_t *sync = j->data;
if(strcmp(sync->treename, treename) == 0) {
local = alpm_db_readpkg(sync->db, targ);
}
}
}
if(local == NULL) {
PM_GRP *grp = NULL;
/* target not found: check if it's a group */
for(j = pmc_syncs; j && !grp; j = j->next) {
sync_t *sync = j->data;
grp = alpm_db_readgrp(sync->db, targ);
if(grp) {
PM_LIST *k, *pkgs;
MSG(NL, ":: group %s:\n", targ);
pkgs = alpm_grp_getinfo(grp, PM_GRP_PKGNAMES);
PM_LIST_display(" ", pkgs);
if(yesno(" Install whole content? [Y/n] ")) {
for(k = alpm_list_first(pkgs); k; k = alpm_list_next(k)) {
targets = list_add(targets, strdup(alpm_list_getdata(k)));
}
} else {
for(k = alpm_list_first(pkgs); k; k = alpm_list_next(k)) {
char *pkgname = alpm_list_getdata(k);
if(yesno(":: Install %s from group %s? [Y/n] ", pkgname, targ)) {
targets = list_add(targets, strdup(pkgname));
}
}
}
}
}
if(grp == NULL) {
ERR(NL, "package \"%s\" not found", targ);
return(1);
}
}
if(treename) {
FREE(targline);
}
}
if(!pmo_s_downloadonly && !pmo_s_printuris) {
/* this is an upgrade, compare versions and determine if it is necessary */
for(i = targets; i; i = i->next) {
int cmp;
PM_PKG *local, *sync;
char *lpkgname, *lpkgver, *spkgver;
local = alpm_db_readpkg(db_local, i->data);
lpkgname = alpm_pkg_getinfo(local, PM_PKG_NAME);
lpkgver = alpm_pkg_getinfo(local, PM_PKG_VERSION);
sync = alpm_db_readpkg(db_local, i->data);
spkgver = alpm_pkg_getinfo(sync, PM_PKG_VERSION);
cmp = alpm_pkg_vercmp(lpkgver, spkgver);
if(cmp > 0) {
/* local version is newer - get confirmation first */
if(!yesno(":: %s-%s: local version is newer. Upgrade anyway? [Y/n] ", lpkgname, lpkgver)) {
/* ORE
char *data = list_remove(targets, lpkgname);
free(data);*/
}
} else if(cmp == 0) {
/* versions are identical */
if(!yesno(":: %s-%s: is up to date. Upgrade anyway? [Y/n] ", lpkgname, lpkgver)) {
/* ORE
char *data = list_remove(targets, lpkgname);
free(data);*/
}
}
}
}
}
/* Step 1: create a new transaction */
if(alpm_trans_init(PM_TRANS_TYPE_SYNC, pmo_flags, NULL) == -1) {
ERR(NL, "failed to init transaction (%s)\n", alpm_strerror(pm_errno));
retval = 1;
goto cleanup;
}
/* and add targets to it */
for(i = targets; i; i = i->next) {
if(alpm_trans_addtarget(i->data) == -1) {
ERR(NL, "failed to add target '%s' (%s)\n", (char *)i->data, alpm_strerror(pm_errno));
retval = 1;
goto cleanup;
}
}
PM_LIST_display("target :", alpm_trans_getinfo(PM_TRANS_TARGETS));
/* ORE
TBD */
/* Step 2: "compute" the transaction based on targets and flags */
if(alpm_trans_prepare(&data) == -1) {
ERR(NL, "failed to prepare transaction (%s)\n", alpm_strerror(pm_errno));
return(1);
}
/* list targets */
if(final && !pmo_s_printuris) {
list_t *list = NULL;
char *str;
unsigned long totalsize = 0;
double mb;
/* ORE
for(i = rmtargs; i; i = i->next) {
list = list_add(list, strdup(i->data));
}
for(i = final; i; i = i->next) {
syncpkg_t *s = (syncpkg_t*)i->data;
for(j = s->replaces; j; j = j->next) {
pkginfo_t *p = (pkginfo_t*)j->data;
list = list_add(list, strdup(p->name));
}
}
if(list) {
printf("\nRemove: ");
str = buildstring(list);
indentprint(str, 9);
printf("\n");
FREELIST(list);
FREE(str);
}*/
/* ORE
for(i = final; i; i = i->next) {
MALLOC(str, strlen(s->pkg->name)+strlen(s->pkg->version)+2);
sprintf(str, "%s-%s", s->pkg->name, s->pkg->version);
list = list_add(list, str);
totalsize += s->pkg->size;
}*/
mb = (double)(totalsize / 1048576.0);
/* round up to 0.1 */
if(mb < 0.1) {
mb = 0.1;
}
printf("\nTargets: ");
str = buildstring(list);
indentprint(str, 9);
printf("\n\nTotal Package Size: %.1f MB\n", mb);
FREELIST(list);
FREE(str);
}
/* get confirmation */
if(pmo_s_downloadonly) {
if(pmo_noconfirm) {
MSG(NL, "\nBeginning download...\n");
confirm = 1;
} else {
confirm = yesno("\nProceed with download? [Y/n] ");
}
} else {
/* don't get any confirmation if we're called from makepkg */
if(pmo_d_resolve || pmo_s_printuris) {
confirm = 1;
} else {
if(pmo_noconfirm) {
MSG(NL, "\nBeginning upgrade process...\n");
confirm = 1;
} else {
confirm = yesno("\nProceed with upgrade? [Y/n] ");
}
}
}
if(!confirm) {
retval = 1;
goto cleanup;
}
/* ORE
group sync records by repository and download */
snprintf(ldir, PATH_MAX, "%svar/cache/pacman/pkg", pmo_root);
while(!done) {
if(current) {
processed = list_add(processed, current);
current = NULL;
}
for(i = final; i; i = i->next) {
if(current == NULL) {
/* we're starting on a new repository */
}
/*if(current && !strcmp(current->treename, sync->dbs->sync->treename)) {
}*/
}
if(files) {
if(pmo_s_printuris) {
server_t *server = (server_t*)current->servers->data;
for(j = files; j; j = j->next) {
if(!strcmp(server->protocol, "file")) {
MSG(NL, "%s://%s%s\n", server->protocol, server->path,
(char *)j->data);
} else {
MSG(NL, "%s://%s%s%s\n", server->protocol,
server->server, server->path, (char *)j->data);
}
}
} else {
struct stat buf;
MSG(NL, "\n:: Retrieving packages from %s...\n", current->treename);
fflush(stdout);
if(stat(ldir, &buf)) {
mode_t oldmask;
/* no cache directory.... try creating it */
/* ORE
* alpm_logaction(stderr, "warning: no %s cache exists. creating...", ldir);*/
oldmask = umask(0000);
if(makepath(ldir)) {
/* couldn't mkdir the cache directory, so fall back to /tmp and unlink
* the package afterwards.
*/
/* ORE
* logaction(stderr, "warning: couldn't create package cache, using /tmp instead");*/
snprintf(ldir, PATH_MAX, "/tmp");
varcache = 0;
}
umask(oldmask);
}
if(downloadfiles(current->servers, ldir, files)) {
ERR(NL, "failed to retrieve some files from %s\n", current->treename);
retval = 1;
goto cleanup;
}
}
count += list_count(files);
FREELIST(files);
}
if(count == list_count(final)) {
done = 1;
}
}
printf("\n");
/* Check integrity of files */
MSG(NL, "checking package integrity... ");
allgood = 1;
for(i = final; i; i = i->next) {
char /*str[PATH_MAX],*/ pkgname[PATH_MAX];
char *md5sum1, *md5sum2;
snprintf(pkgname, PATH_MAX, "%s-%s.pkg.tar.gz", "", "");
md5sum1 = NULL;
md5sum2 = NULL;
if(strcmp(md5sum1, md5sum2) != 0) {
if(allgood) {
printf("\n");
}
ERR(NL, "error: archive %s is corrupted\n", "");
allgood = 0;
}
FREE(md5sum2);
}
if(!allgood) {
retval = 1;
goto cleanup;
}
MSG(CL, "done.\n");
/* Step 3: actually perform the installation */
if(!pmo_s_downloadonly) {
if(alpm_trans_commit(&data) == -1) {
ERR(NL, "failed to commit transaction (%s)\n", alpm_strerror(pm_errno));
retval = 1;
goto cleanup;
}
}
if(!varcache && !pmo_s_downloadonly) {
/* delete packages */
for(i = files; i; i = i->next) {
unlink(i->data);
}
}
cleanup:
return(retval);
}
/* vim: set ts=2 sw=2 noet: */

35
src/pacman/sync.h Normal file
View File

@ -0,0 +1,35 @@
/*
* sync.h
*
* Copyright (c) 2002-2005 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 _PM_SYNC_H
#define _PM_SYNC_H
/* Repositories */
typedef struct __sync_t {
char *treename;
PM_DB *db;
list_t *servers; /* List of server_t */
} sync_t;
int pacman_sync(list_t *targets);
#endif /* _PM_SYNC_H */
/* vim: set ts=2 sw=2 noet: */

42
src/pacman/upgrade.c Normal file
View File

@ -0,0 +1,42 @@
/*
* upgrade.c
*
* Copyright (c) 2002-2005 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <alpm.h>
/* pacman */
#include "list.h"
#include "add.h"
extern unsigned char pmo_upgrade;
int pacman_upgrade(list_t *targets)
{
/* this is basically just a remove-then-add process. pacman_add() will */
/* handle it */
pmo_upgrade = 1;
return(pacman_add(targets));
}
/* vim: set ts=2 sw=2 noet: */

28
src/pacman/upgrade.h Normal file
View File

@ -0,0 +1,28 @@
/*
* upgrade.h
*
* Copyright (c) 2002-2005 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 _PM_UPGRADE_H
#define _PM_UPGRADE_H
int pacman_upgrade(list_t *targets);
#endif /* _PM_UPGRADE_H */
/* vim: set ts=2 sw=2 noet: */

297
src/pacman/util.c Normal file
View File

@ -0,0 +1,297 @@
/*
* util.c
*
* Copyright (c) 2002-2005 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 "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <dirent.h>
#include <zlib.h>
#include <libtar.h>
/* pacman */
#include "util.h"
/* borrowed and modified from Per Liden's pkgutils (http://crux.nu) */
long 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 (long)gzf;
}
int unpack(char *archive, const char *prefix, const char *fn)
{
TAR *tar = NULL;
char expath[PATH_MAX];
tartype_t gztype = {
(openfunc_t) gzopen_frontend,
(closefunc_t)gzclose,
(readfunc_t) gzread,
(writefunc_t)gzwrite
};
/* open the .tar.gz package */
if(tar_open(&tar, archive, &gztype, O_RDONLY, 0, TAR_GNU) == -1) {
perror(archive);
return(1);
}
while(!th_read(tar)) {
if(fn && strcmp(fn, th_get_pathname(tar))) {
if(TH_ISREG(tar) && tar_skip_regfile(tar)) {
char errorstr[255];
snprintf(errorstr, 255, "bad tar archive: %s", archive);
perror(errorstr);
tar_close(tar);
return(1);
}
continue;
}
snprintf(expath, PATH_MAX, "%s/%s", prefix, th_get_pathname(tar));
if(tar_extract_file(tar, expath)) {
fprintf(stderr, "could not extract %s: %s\n", th_get_pathname(tar), strerror(errno));
}
if(fn) break;
}
tar_close(tar);
return(0);
}
/* does the same thing as 'mkdir -p' */
int makepath(char *path)
{
char *orig, *str, *ptr;
char full[PATH_MAX] = "";
mode_t oldmask;
oldmask = umask(0000);
orig = strdup(path);
str = orig;
while((ptr = strsep(&str, "/"))) {
if(strlen(ptr)) {
struct stat buf;
strcat(full, "/");
strcat(full, ptr);
if(stat(full, &buf)) {
if(mkdir(full, 0755)) {
free(orig);
umask(oldmask);
return(1);
}
}
}
}
free(orig);
umask(oldmask);
return(0);
}
/* does the same thing as 'rm -rf' */
int rmrf(char *path)
{
int errflag = 0;
struct dirent *dp;
DIR *dirp;
char name[PATH_MAX];
extern int errno;
if(!unlink(path)) {
return(0);
} else {
if(errno == ENOENT) {
return(0);
} else if(errno == EPERM) {
/* fallthrough */
} else if(errno == EISDIR) {
/* fallthrough */
} else if(errno == ENOTDIR) {
return(1);
} else {
/* not a directory */
return(1);
}
if((dirp = opendir(path)) == (DIR *)-1) {
return(1);
}
for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
if(dp->d_ino) {
sprintf(name, "%s/%s", path, dp->d_name);
if(strcmp(dp->d_name, "..") && strcmp(dp->d_name, ".")) {
errflag += rmrf(name);
}
}
}
closedir(dirp);
if(rmdir(path)) {
errflag++;
}
return(errflag);
}
return(0);
}
/* output a string, but wrap words properly with a specified indentation
*/
void indentprint(char *str, int indent)
{
char *p = str;
char *cenv = NULL;
int cols = 80;
int cidx = indent;
cenv = getenv("COLUMNS");
if(cenv) {
cols = atoi(cenv);
}
while(*p) {
if(*p == ' ') {
char *next = NULL;
int len;
p++;
if(p == NULL || *p == ' ') continue;
next = strchr(p, ' ');
if(next == NULL) {
next = p + strlen(p);
}
len = next - p;
if(len > (cols-cidx-1)) {
/* newline */
int i;
fprintf(stdout, "\n");
for(i = 0; i < indent; i++) {
fprintf(stdout, " ");
}
cidx = indent;
} else {
printf(" ");
cidx++;
}
}
fprintf(stdout, "%c", *p);
p++;
cidx++;
}
}
/* 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 *strtrim(char *str)
{
char *pch = str;
while(isspace(*pch)) {
pch++;
}
if(pch != str) {
memmove(str, pch, (strlen(pch) + 1));
}
pch = (char *)(str + (strlen(str) - 1));
while(isspace(*pch)) {
pch--;
}
*++pch = '\0';
return str;
}
/* presents a prompt and gets a Y/N answer
*/
int yesno(char *fmt, ...)
{
char response[32];
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
fflush(stdout);
if(fgets(response, 32, stdin)) {
/* trim whitespace and newlines */
char *pch = response;
while(isspace(*pch)) {
pch++;
}
if(pch != response) {
memmove(response, pch, strlen(pch) + 1);
}
pch = response + strlen(response) - 1;
while(isspace(*pch)) {
pch--;
}
*++pch = 0;
strtrim(response);
if(!strcasecmp(response, "Y") || !strcasecmp(response, "YES") || !strlen(response)) {
return(1);
}
}
return(0);
}
/* vim: set ts=2 sw=2 noet: */

42
src/pacman/util.h Normal file
View File

@ -0,0 +1,42 @@
/*
* util.h
*
* Copyright (c) 2002-2005 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 _PM_UTIL_H
#define _PM_UTIL_H
#define MALLOC(p, b) do { if((b) > 0) { \
p = malloc(b); if (!(p)) { \
fprintf(stderr, "malloc failure: could not allocate %d bytes\n", b); \
exit(1); }} else p = NULL; } while(0)
#define FREE(p) do { if (p) { free(p); (p)= NULL; }} while(0)
long gzopen_frontend(char *pathname, int oflags, int mode);
int unpack(char *archive, const char *prefix, const char *fn);
int makepath(char *path);
int rmrf(char *path);
void indentprint(char *str, int indent);
char *strtrim(char *str);
char *strtoupper(char *str);
int yesno(char *fmt, ...);
#endif /* _PM_UTIL_H */
/* vim: set ts=2 sw=2 noet: */

146
src/util/convertdb.c Normal file
View File

@ -0,0 +1,146 @@
/*
* convertdb.c
*
* Copyright (c) 2002-2005 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 <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "pacconf.h"
#include "list.h"
#include "util.h"
unsigned short pmo_verbose = 0;
int main(int argc, char* argv[])
{
FILE* db = NULL;
FILE* fp = NULL;
char* ptr = NULL;
char name[256];
char ver[256];
char line[PATH_MAX+1];
char topdir[PATH_MAX+1];
char path[PATH_MAX+1];
mode_t oldumask;
struct stat buf;
char dbdir[PATH_MAX];
sprintf(dbdir, "/%s", PACDBDIR);
if(argc < 2) {
printf("converts a pacman 1.x database to a pacman 2.0 format\n");
printf("usage: %s <target_dir>\n\n", basename(argv[0]));
printf("convertdb will convert all package data from /var/lib/pacman/pacman.db\n");
printf("to a 2.0 format and place it in target_dir.\n\n");
return(0);
}
db = fopen(dbdir, "r");
if(db == NULL) {
perror(dbdir);
return(1);
}
oldumask = umask(0000);
while(fgets(name, 255, db)) {
PMList *backup = NULL;
PMList *lp;
if(!fgets(ver, 255, db)) {
perror(dbdir);
return(1);
}
trim(name);
trim(ver);
fprintf(stderr, "converting %s\n", name);
/* package directory */
snprintf(topdir, PATH_MAX, "%s/%s-%s", argv[1], name, ver);
mkdir(topdir, 0755);
/* DESC */
snprintf(path, PATH_MAX, "%s/desc", topdir);
if(!(fp = fopen(path, "w"))) {
perror(path);
return(1);
}
fputs("%NAME%\n", fp);
fprintf(fp, "%s\n\n", name);
fputs("%VERSION%\n", fp);
fprintf(fp, "%s\n\n", ver);
fputs("%DESC%\n\n", fp);
fclose(fp);
/* DEPENDS */
snprintf(path, PATH_MAX, "%s/depends", topdir);
if(!(fp = fopen(path, "w"))) {
perror(path);
return(1);
}
fputs("%DEPENDS%\n\n", fp);
fputs("%REQUIREDBY%\n\n", fp);
fputs("%CONFLICTS%\n\n", fp);
fclose(fp);
/* FILES */
snprintf(path, PATH_MAX, "%s/files", topdir);
if(!(fp = fopen(path, "w"))) {
perror(path);
return(1);
}
fputs("%FILES%\n", fp);
while(fgets(line, 255, db) && strcmp(trim(line), "")) {
trim(line);
ptr = line;
/* check for backup designation and frontslashes that shouldn't be there */
if(line[0] == '*') ptr++;
if(*ptr == '/') ptr++;
if(line[0] == '*') backup = list_add(backup, strdup(ptr));
fprintf(fp, "%s\n", ptr);
}
fprintf(fp, "\n");
fputs("%BACKUP%\n", fp);
for(lp = backup; lp; lp = lp->next) {
/* print the filename and a bad md5 hash. we just use 32 f's cuz we can't
* md5 the original file since we don't have it
*/
fprintf(fp, "%s\tffffffffffffffffffffffffffffffff\n", (char*)lp->data);
}
fputs("\n", fp);
fclose(fp);
snprintf(path, PATH_MAX, "/var/lib/pacman/scripts/%s", name);
if(!stat(path, &buf)) {
snprintf(line, PATH_MAX, "/bin/cp %s %s/install", path, topdir);
system(line);
}
list_free(backup);
}
umask(oldumask);
return(0);
}
/* vim: set ts=2 sw=2 noet: */

45
src/util/vercmp.c Normal file
View File

@ -0,0 +1,45 @@
/*
* vercmp.c
*
* Copyright (c) 2002-2005 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 <stdio.h>
#include <string.h>
#include "rpmvercmp.h"
int main(int argc, char *argv[])
{
char s1[255] = "";
char s2[255] = "";
int ret;
if(argc > 1) {
strncpy(s1, argv[1], 255);
}
if(argc > 2) {
strncpy(s2, argv[2], 255);
} else {
printf("0\n");
return(0);
}
ret = rpmvercmp(s1, s2);
printf("%d\n", ret);
return(ret);
}