mirror of
https://github.com/moparisthebest/pacman
synced 2024-10-31 15:45:03 -04:00
Initial revision
This commit is contained in:
commit
d04baabafa
340
COPYING
Normal file
340
COPYING
Normal 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
268
ChangeLog
Normal 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
288
README
Normal 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
23
TODO
Normal 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?
|
||||
|
407
doc/makepkg.8.in
Normal file
407
doc/makepkg.8.in
Normal 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
312
doc/pacman.8.in
Normal 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
36
etc/makepkg.conf
Normal 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
53
etc/pacman.conf
Normal 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
39
lib/libalpm/Makefile
Normal 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
580
lib/libalpm/add.c
Normal 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
34
lib/libalpm/add.h
Normal 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
577
lib/libalpm/alpm.c
Normal 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
330
lib/libalpm/alpm.h
Normal 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
63
lib/libalpm/backup.c
Normal 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
30
lib/libalpm/backup.h
Normal 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
203
lib/libalpm/cache.c
Normal 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
42
lib/libalpm/cache.h
Normal 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
651
lib/libalpm/db.c
Normal 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
60
lib/libalpm/db.h
Normal 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
685
lib/libalpm/deps.c
Normal 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
35
lib/libalpm/deps.h
Normal 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
90
lib/libalpm/error.c
Normal 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
30
lib/libalpm/error.h
Normal 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
67
lib/libalpm/group.c
Normal 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
48
lib/libalpm/group.h
Normal 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
229
lib/libalpm/handle.c
Normal 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
63
lib/libalpm/handle.h
Normal 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
210
lib/libalpm/list.c
Normal 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
50
lib/libalpm/list.h
Normal 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
52
lib/libalpm/log.c
Normal 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
32
lib/libalpm/log.h
Normal 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
338
lib/libalpm/md5.c
Normal 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
51
lib/libalpm/md5.h
Normal 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
81
lib/libalpm/md5driver.c
Normal 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
342
lib/libalpm/package.c
Normal 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
78
lib/libalpm/package.h
Normal 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
53
lib/libalpm/provide.c
Normal 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
33
lib/libalpm/provide.h
Normal 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
259
lib/libalpm/remove.c
Normal 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
34
lib/libalpm/remove.h
Normal 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
237
lib/libalpm/rpmvercmp.c
Normal 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
32
lib/libalpm/rpmvercmp.h
Normal 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
248
lib/libalpm/sync.c
Normal 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
47
lib/libalpm/sync.h
Normal 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
187
lib/libalpm/trans.c
Normal 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
54
lib/libalpm/trans.h
Normal 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
401
lib/libalpm/util.c
Normal 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
57
lib/libalpm/util.h
Normal 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
68
lib/libftp/Makefile
Normal 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
1569
lib/libftp/ftplib.c
Normal file
File diff suppressed because it is too large
Load Diff
131
lib/libftp/ftplib.h
Normal file
131
lib/libftp/ftplib.h
Normal 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
186
scripts/gensync
Executable 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
701
scripts/makepkg
Executable 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
143
scripts/makeworld
Executable 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
231
scripts/updatesync
Executable 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
39
src/pacman/Makefile
Normal 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
130
src/pacman/add.c
Normal 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
28
src/pacman/add.h
Normal 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
308
src/pacman/conf.c
Normal 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
28
src/pacman/conf.h
Normal 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
98
src/pacman/db.c
Normal 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
28
src/pacman/db.h
Normal 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
467
src/pacman/download.c
Normal 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
38
src/pacman/download.h
Normal 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
176
src/pacman/list.c
Normal 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
45
src/pacman/list.h
Normal 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
203
src/pacman/package.c
Normal 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
35
src/pacman/package.h
Normal 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
688
src/pacman/pacman.c
Normal 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
75
src/pacman/pacman.h
Normal 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
247
src/pacman/query.c
Normal 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
28
src/pacman/query.h
Normal 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
137
src/pacman/remove.c
Normal 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
28
src/pacman/remove.h
Normal 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
806
src/pacman/sync.c
Normal 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
35
src/pacman/sync.h
Normal 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
42
src/pacman/upgrade.c
Normal 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
28
src/pacman/upgrade.h
Normal 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
297
src/pacman/util.c
Normal 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
42
src/pacman/util.h
Normal 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
146
src/util/convertdb.c
Normal 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
45
src/util/vercmp.c
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user