Compare commits

...

No commits in common. "master" and "import-tars" have entirely different histories.

873 changed files with 23016 additions and 270108 deletions

View file

@ -1,24 +0,0 @@
# EditorConfig configuration for pacman
# https://editorconfig.org
# Top-most EditorConfig file
root = true
# Unix-style newlines without trailing whitespaces, but with a newline
# ending every file, utf-8 charset, set indent to tabs
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
indent_style = tab
[{NEWS,HACKING}]
indent_style = space
[meson.build]
indent_style = space
indent_size = 2
[*.py]
indent_style = space

1
.gitattributes vendored
View file

@ -1 +0,0 @@
*.py diff=python

3
.gitignore vendored
View file

@ -1,3 +0,0 @@
*~
*.o
pacman-*.tar.gz

View file

@ -1,132 +0,0 @@
variables:
MAKEFLAGS: "-j10"
VERBOSE: 1
default:
after_script:
- build-aux/print-failed-test-output build/meson-logs/testlog.json
.arch-test:
image: archlinux:base-devel
before_script:
- >
pacman -Syu --needed --noconfirm
git
gpgme libarchive curl
python
fakeroot fakechroot
meson
artifacts:
when: always
paths:
- build/meson-logs/meson-log.txt
arch:
extends: .arch-test
script:
- meson setup build
- ninja -C build
- fakechroot meson test -C build
arch-debug:
extends: .arch-test
script:
- meson setup --buildtype=debug --werror build
- ninja -C build
- fakechroot meson test -C build
arch-docs:
extends: .arch-test
script:
- pacman -Syu --needed --noconfirm asciidoc
- meson setup -Ddoc=enabled build
- ninja -C build
arch-clang:
extends: .arch-test
script:
- pacman -Syu --needed --noconfirm clang
- CC=clang meson setup build
- ninja -C build
- fakechroot meson test -C build
#arch-valgrind:
# extends: .arch-test
# script:
# - pacman -Syu --needed --noconfirm valgrind
# - pacman -U --noconfirm https://geo.mirror.pkgbuild.com/core-debug/os/x86_64/glibc-debug-$(pacman -S --print-format %v glibc)-x86_64.pkg.tar.zst
# - meson setup build
# - ninja -C build
# - PACTEST_VALGRIND=1 fakechroot meson test -C build
arch-nettle:
extends: .arch-test
script:
- meson setup -Dcrypto=nettle --buildtype=debug build
- ninja -C build
- fakechroot meson test -C build
arch-no-gpg:
extends: .arch-test
script:
- meson setup -Dgpgme=disabled --buildtype=debug build
- ninja -C build
- fakechroot meson test -C build
arch-no-curl:
extends: .arch-test
script:
- meson setup -Dcurl=disabled --buildtype=debug build
- ninja -C build
- fakechroot meson test -C build
arch-no-nls:
extends: .arch-test
script:
- meson setup -Di18n=false --buildtype=debug build
- ninja -C build
- fakechroot meson test -C build
debian:
image: debian:bookworm
before_script:
- apt update
- >
apt -y install --no-install-recommends
git pkg-config meson gcc libtool
libgpgme-dev libarchive-dev libcurl4-openssl-dev libssl-dev curl
gettext python3 python3-setuptools dash gawk ca-certificates
fakeroot fakechroot
script:
- meson setup --buildtype=debug build
- ninja -C build
- fakechroot meson test -C build
fedora:
image: fedora
before_script:
- >
dnf -y install
git findutils patch sed
meson gcc libtool bsdtar
gpgme-devel libarchive-devel libcurl-devel openssl-devel gettext-devel
asciidoc python3 dash gawk
fakeroot fakechroot
perl-Module-Load-Conditional
script:
- meson setup --buildtype=debug build
- ninja -C build
- fakechroot meson test -C build
pages:
extends: .arch-test
script:
- pacman -Syu --needed --noconfirm asciidoc
- meson setup -Ddoc=enabled build
- ninja -C build html
artifacts:
paths:
- build/doc
publish: build/doc
rules:
- if: $CI_COMMIT_BRANCH == "release/6.1.x"

View file

@ -1,35 +0,0 @@
Aaron Griffin <aaron@archlinux.org> <aaronmgriffin@gmail.com>
Allan McRae <allan@archlinux.org> <mcrae_allan@hotmail.com>
Allan McRae <allan@archlinux.org> <mcrae_allan at hotmail.com>
Allan McRae <allan@archlinux.org> <allan.mcrae@qimr.edu.au>
Andres P <aepd87@gmail.com> <stderr@mail.com>
Andrew Gregory <andrew.gregory.8@gmail.com>
Barbu Paul - Gheorghe <barbu.paul.gheorghe@gmail.com>
Bryan Ischo <bryan@ischo.com> <bji-keyword-pacman.3644cb@www.ischo.com>
Christos Nouskas <nous@archlinux.us> <nouskas@gmail.com>
Daenyth Blank <daenyth+arch@gmail.com> <Daenyth+Arch@gmail.com>
Daenyth Blank <Daenyth+arch@gmail.com> <Daenyth+git@gmail.com>
Dave Reisner <dreisner@archlinux.org> <d@falconindy.com>
甘露(Gan Lu) <rhythm.gan@gmail.com>
Giovanni Scafora <giovanni@archlinux.org> <linuxmania@gmail.com>
Jan Alexander Steffens (heftig) <heftig@archlinux.org> <jan.steffens@gmail.com>
Jaroslaw Swierczynski <swiergot@gmail.com> <swiergot@juvepoland.com>
Jonathan Conder <j@skurvy.no-ip.org> <jonno.conder@gmail.com>
Juan Pablo González Tognarelli <lord_jotape@yahoo.com.ar>
Juan Pablo González Tognarelli <lord_jotape@yahoo.com.ar> <jotapesan@gmail.com>
Manuel Tortosa <manutortosa@chakra-project.org> <manutortosa@gmail.com>
Marc - A. Dahlhaus <mad@wol.de>
Matthias Gorissen <matthias@archlinux.de> <siquame@web.de>
morganamilo <morganamilo@archlinux.org> <morganamilo@gmail.com>
Laszlo Papp <djszapi@archlinux.us> <djszapi2@gmail.com>
Nagy Gabor <ngaba@bibl.u-szeged.hu> <ngaba@petra.hos.u-szeged.hu>
Nagy Gabor <ngaba@bibl.u-szeged.hu> <ngaba at bibl.u-szeged.hu>
Nezmer <git@nezmer.info> <Nezmer@allurelinux.org>
Roman Kyrylych <roman@archlinux.org> <roman.kyrylych@gmail.com>
Sebastian Nowicki <sebnow@gmail.com> <xilonmu@gmail.com>
Vojtěch Gondžala <vojtech.gondzala@gmail.com> <vogo@seznam.cz>
Vojtěch Gondžala <vojtech.gondzala@gmail.com> Vojtech Gondzala <vojtech.gondzala@gmail.com>
William Giokas <1007380@gmail.com>
Xavier Chantry <shiningxc@gmail.com>
Xavier Chantry <shiningxc@gmail.com> <chantry.xavier@gmail.com>
Xavier Chantry <shiningxc@gmail.com> <xav@chantry.homelinux.org>

View file

@ -1,18 +0,0 @@
[main]
host = https://www.transifex.com
[o:toofishes:p:archlinux-pacman:r:libalpm-pot]
file_filter = lib/libalpm/po/<lang>.po
source_file = lib/libalpm/po/libalpm.pot
source_lang = en
[o:toofishes:p:archlinux-pacman:r:pacman-pot]
file_filter = src/pacman/po/<lang>.po
source_file = src/pacman/po/pacman.pot
source_lang = en
[o:toofishes:p:archlinux-pacman:r:pacman-scripts-pot]
file_filter = scripts/po/<lang>.po
source_file = scripts/po/pacman-scripts.pot
source_lang = en

View file

@ -1 +0,0 @@
Use `git shortlog -s` for a list of contributors.

31
COPYING
View file

@ -1,8 +1,9 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
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.
@ -15,7 +16,7 @@ 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 Lesser General Public License instead.) You can apply it to
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
@ -55,7 +56,7 @@ 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
@ -110,7 +111,7 @@ above, provided that you also meet all of these conditions:
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
@ -168,7 +169,7 @@ 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
@ -225,7 +226,7 @@ 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
@ -278,8 +279,8 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
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
@ -291,7 +292,7 @@ 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) <year> <name of author>
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
@ -303,16 +304,16 @@ the "copyright" line and a pointer to where the full notice is found.
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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
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) year name of author
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.
@ -335,5 +336,5 @@ necessary. Here is a sample; alter the names:
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 Lesser General
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

308
ChangeLog Normal file
View file

@ -0,0 +1,308 @@
VERSION DESCRIPTION
-----------------------------------------------------------------------------
2.9.8 - Changed behaviour with original=X,current=Y,new=Z scenario
- keep old in place, install new as .pacnew
- Search package provides when finding matching targets with -S
- Frugalware: added -Qm option to find foreign packages
- Frugalware: added DistCC support to makepkg
- bugfix: before searching databases for a dependency, make sure
one of the packages in the final list doesn't already provide
that dependency
- fix for segfaults that occurred when propagating requiredby
fields to replaced packages where one package depended on
another replaced package
- a better fix for pacman-optimize integrity checks
- fix for regex searches with -Ss (Miklos Vajna)
- added a --noprogressbar for scripts to use
2.9.7 - fixed the dupe listings of packages when dealing w/ groups
- patches from Miklos Vajna:
- add regexp search support for -Qs and -Ss
- fixed md5sums on x86_64
- add --sudosync to makepkg
- show syntax help if an invalid option is used
- added makepkg option to disable ccache support
- changed license field to operate as an array, not a string
- added more logic for file conflict checks - if one target
is a file and the other is a directory, then it's a conflict
- fixed the integrity check in pacman-optimize
- reverted NoUpgrade to old behaviour and instead, added the
NoExtract directive to pacman.conf, which prevents a file
from ever being extracted on to the system
eg, NoExtract = home/httpd/html/index.html
2.9.6 - added a pacman-optimize script to try and defragment the DB
- modified NoUpgrade behaviour to avoid extracting files
that are missing from the filesystem -- this helps in
situations where the admin does not want the file there, eg,
remove index.html so index.php takes precedence
- fixed a bug where files would sometimes go missing if they
moved from one package to another
- add db_remove() which is responsible for clearing out stale
hash table entries when packages are removed
- added ccache support to makepkg
- patch from Aurelien Foret fixes a few memory leaks
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

178
HACKING
View file

@ -1,178 +0,0 @@
Pacman - Contributing
=====================
This file is meant to give you a brief overview of coding style and other
concerns when hacking on pacman. If you are interested in contributing, please
read link:submitting-patches.html[submitting-patches] and
link:translation-help.html[translation-help] as well.
Coding Style
------------
1. All code should be indented with tabs. (Ignore the use of only spaces in
this file.) A tab size of two spaces is used when calculating line widths,
which should be a maximum of 80 characters. An EditorConfig file is used
to set this project-wide default.
2. When opening new blocks such as 'while', 'if', or 'for', leave the opening
brace on the same line as the beginning of the codeblock. The closing brace
gets its own line (the only exception being 'else'). Do not use extra
spaces around the parentheses of the block. ALWAYS use opening and closing
braces, even if it's just a one-line block. This reduces future error when
blocks are expanded beyond one line.
+
[source,C]
-------------------------------------------
for(lp = list; lp; lp = lp->next) {
newlist = _alpm_list_add(newlist, strdup(lp->data));
}
while(it) {
ptr = it->next;
if(fn) {
fn(it->data);
} else {
return 1;
}
free(it);
it = ptr;
}
-------------------------------------------
3. When declaring a new function, put the opening and closing braces on their
own line. Also, when declaring a pointer, do not put a space between the
asterisk and the variable name.
+
[source,C]
-------------------------------------------
alpm_list_t *alpm_list_add(alpm_list_t *list, void *data)
{
alpm_list_t *ptr, *lp;
ptr = list;
if(ptr == NULL) {
...
}
...
}
-------------------------------------------
4. Comments should be ANSI-C89 compliant. That means no `// Comment` style;
use only `/* Comment */` style.
/* This is a comment */
NOT
// This is a comment
5. Return statements should *not* be written like function calls.
return 0;
NOT
return(0);
6. When using strcmp() (or any function that returns 0 on success) in a
conditional statement, use != 0 or == 0 and not the negation (!) operator.
It reads much cleaner for humans (using a negative to check for success is
confusing) and the compiler will treat it correctly anyway.
if(strcmp(a, b) == 0)
NOT
if(!strcmp(a, b))
7. Use spaces around almost all arithmetic, comparison and assignment
operators and after all ',;:' separators.
foobar[2 * size + 1] = function(a, 6);
NOT
foobar[2*size+1]=function(a,6);
for(a = 0; a < n && n > 0; a++, n--) {}
NOT
for(a=0;a<n&&n>0;a++,n--) {}
8. Declare all variables at the start of the block.
[source,C]
-------------------------------------------
int SYMEXPORT alpm_db_remove_server(alpm_db_t *db, const char *url)
{
char *newurl, *vdata = NULL;
newurl = url;
if(!newurl) {
return -1;
}
...
if(vdata) {
...
}
return 1;
}
-------------------------------------------
NOT
[source,C]
-------------------------------------------
int SYMEXPORT alpm_db_remove_server(alpm_db_t *db, const char *url)
{
char *newurl = url;
if(!newurl) {
return -1;
}
char *vdata = NULL;
if(vdata) {
...
}
return 1;
}
-------------------------------------------
Other Concerns
--------------
Header Includes
~~~~~~~~~~~~~~~
Currently our #include usage is in messy shape, but this is no reason to
continue down this messy path. When adding an include to a file, follow this
general pattern, including blank lines:
[source,C]
-------------------------------------------
#include <standardheader.h>
#include <another.h>
#include <...>
-------------------------------------------
Follow this with some more headers, depending on whether the file is in libalpm
or pacman proper. For libalpm:
[source,C]
-------------------------------------------
/* libalpm */
#include "yourfile.h"
#include "alpm_list.h"
#include "anythingelse.h"
-------------------------------------------
For pacman:
[source,C]
-------------------------------------------
#include <alpm.h>
#include <alpm_list.h>
/* pacman */
#include "yourfile.h"
#include "anythingelse.h"
-------------------------------------------
Never directly include config.h. This will always be added via Makefiles.

124
Makefile.in Normal file
View file

@ -0,0 +1,124 @@
#
# pacman
#
# Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
# USA.
#
# NOTE: Since pacman is compiled statically, you will need the static
# libraries for zlib and glibc.
DESTDIR =
prefix = @prefix@
exec_prefix = @prefix@
BINDIR = @bindir@
MANDIR = @mandir@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
INSTALL_DATA = @INSTALL_DATA@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
PACVER = 2.9.8
TOPDIR = @srcdir@
SRCDIR = $(TOPDIR)/src/
OBJDIR = $(TOPDIR)/src/
MANSRC = $(TOPDIR)/doc/
SCRDIR = $(TOPDIR)/scripts/
CXX = @CC@
CXXFLAGS += @CFLAGS@ -g -Wall -pedantic -fno-exceptions \
-D_GNU_SOURCE -DPACVER=\"$(PACVER)\" -I. -Ilibftp
LDFLAGS += @LDFLAGS@ -Llibftp -lftp -ltar -lz
SRCS = $(SRCDIR)pacman.c \
$(SRCDIR)db.c \
$(SRCDIR)util.c \
$(SRCDIR)list.c \
$(SRCDIR)package.c \
$(SRCDIR)pacsync.c \
$(SRCDIR)md5.c \
$(SRCDIR)md5driver.c \
$(SRCDIR)strhash.c \
$(SRCDIR)vercmp.c \
$(SRCDIR)rpmvercmp.c
OBJECTS = $(OBJDIR)pacman.o \
$(OBJDIR)db.o \
$(OBJDIR)util.o \
$(OBJDIR)list.o \
$(OBJDIR)package.o \
$(OBJDIR)pacsync.o \
$(OBJDIR)md5.o \
$(OBJDIR)md5driver.o \
$(OBJDIR)strhash.o \
$(OBJDIR)rpmvercmp.o
all: libftp.a pacman vercmp convertdb man
pacman: $(OBJECTS) libftp.a
$(CXX) $(OBJECTS) -o $@ $(LDFLAGS)
$(CXX) $(OBJECTS) -o $@.static -static $(LDFLAGS)
vercmp: $(OBJDIR)vercmp.o $(OBJDIR)rpmvercmp.o
$(CXX) $(OBJDIR)vercmp.o $(OBJDIR)rpmvercmp.o $(CXXFLAGS) -o $@
convertdb: $(OBJDIR)convertdb.o $(OBJDIR)list.o $(OBJDIR)util.o
$(CXX) $(OBJDIR)convertdb.o $(OBJDIR)list.o $(OBJDIR)util.o $(LDFLAGS) -o $@
.c.o: $(SRCS)
$(CXX) $(CXXFLAGS) -o $@ -c $<
man: $(MANSRC)pacman.8 \
$(MANSRC)makepkg.8
%.8: %.8.in
sed -e "s/#VERSION#/$(PACVER)/" $< > $@
dist: distclean
(cd ..; tar czvf pacman-$(PACVER).tar.gz pacman-$(PACVER))
libftp.a:
(cd libftp; make libftp.a)
install: pacman vercmp convertdb man
$(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
$(INSTALL) -D -m0755 $(SCRDIR)makepkg $(DESTDIR)$(BINDIR)/makepkg
$(INSTALL) -D -m0755 $(SCRDIR)makeworld $(DESTDIR)$(BINDIR)/makeworld
$(INSTALL) -D -m0755 $(SCRDIR)gensync $(DESTDIR)$(BINDIR)/gensync
$(INSTALL) -D -m0755 $(SCRDIR)updatesync $(DESTDIR)$(BINDIR)/updatesync
$(INSTALL) -D -m0755 $(SCRDIR)pacman-optimize $(DESTDIR)$(BINDIR)/pacman-optimize
$(INSTALL) -D -m0644 $(MANSRC)pacman.8 $(DESTDIR)$(MANDIR)/man8/pacman.8
$(INSTALL) -D -m0644 $(MANSRC)makepkg.8 $(DESTDIR)$(MANDIR)/man8/makepkg.8
$(INSTALL) -D -m0644 etc/pacman.conf $(DESTDIR)/etc/pacman.conf
$(INSTALL) -D -m0644 etc/makepkg.conf $(DESTDIR)/etc/makepkg.conf
clean:
rm -f *~ $(OBJDIR)*.o $(MANSRC)*.8
(cd libftp; make clobber)
distclean: clean
rm -f pacman pacman.static convertdb vercmp
rm -f Makefile
rm -f config.h config.status config.log
# End of file

1716
NEWS

File diff suppressed because it is too large Load diff

788
README
View file

@ -1,758 +1,64 @@
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, while not exhaustive, also
indicates some limitations (on purpose, or sometimes due to its poor design) of
the library at the present time.
pacman - Package Management Utility
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.
by Judd Vinet <jvinet@zeroflux.org>
<http://www.archlinux.org/pacman/>
In addition to "alpm.h", the interfaces of "alpm_list.h" have also been made
available to the frontend, for allowing it to manipulate the lists returned by
the backend.
DESCRIPTION:
------------
pacman is a utility which manages software packages in Linux. It uses
simple .tar.gz files as a package format, and maintains a text-based
package database (more of a hierarchy), just in case some hand tweaking
is necessary.
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, internal function
names have been prepended with "_alpm_".
pacman does not strive to "do everything." It will add, remove and
upgrade packages in the system, and it will allow you to query the
package database for installed packages, files and owners. It also
attempts to handle dependencies automatically and can download packages
from a remote server.
In a general manner, public library functions are named "alpm_<type>_<action>"
(examples: alpm_trans_commit(), alpm_release(), alpm_pkg_get_name(), ...).
Internal (and thus private) functions should be named "_alpm_XXX" for instance
(examples: _alpm_needbackup(), _alpm_runscriplet(), ...). Functions defined and
used inside a single file should be defined as "static".
Although the package manager itself is quite simple, the pacman tarball
also comes with scripts that help automate building and installing
packages. These are used extensively in the Arch Build System (ABS),
used in Arch Linux <http://www.archlinux.org>.
As of version 2.0, pacman can also keep your system's packages in
sync with a master server. You can follow CURRENT and STABLE trees,
or lock yourself into a specific version. See the pacman manpage
for more info on this (--sync operation).
[Initialization]
alpm_initialize() is used to initialize library internals and to create
a transparent handle object. Before its call, the library can't be used.
INSTALL:
--------
$ ./configure
$ make
# make install
alpm_release() just does the opposite (memory used by the library, and the
handle is freed). After its call, the library is no longer available.
If your man files are located in a directory other than /usr/man, you may
want to edit Makefile and modify the MANDIR line accordingly.
Note: Since pacman is compiled statically, you will need the static libraries
for libtar, glibc and zlib.
[Options]
The library does not use any configuration file. It is up to the front end to
configure the library as needed; the handle holds a number of configuration
options instead.
BUGS:
-----
If you find bugs (which is quite likely), please submit them to
<jvinet@zeroflux.org> with specific information such as your
commandline, the nature of the bug, and even the package database if
it helps.
All of the following options have a alpm_option_get_* and alpm_option_set_*
function for getting and setting the value. They cannot be set before the
library is initialized.
* logcb: The callback function for "log" operations.
* dlcb: The callback function for download progress of each package.
* fetchcb: Callback for custom download function.
* eventcb: Callback for transaction messages.
* questioncb: Callback for selecting amongst choices.
* progresscb: Callback to handle display of transaction progress.
* gpgdir: Directory where GnuPG files are stored.
* arch: Allowed package architecture.
* checkspace: Check disk space before installing.
* default_siglevel: Default signature verification level.
* local_file_siglevel: Signature verification level for local file upgrades.
* remote_file_siglevel: Signature verification level for remote file upgrades.
* logfile: The base path to pacman's log file (Default: /var/log/pacman.log)
* usesyslog: Log to syslog instead of `logfile` for file-base logging.
COPYRIGHT:
----------
pacman is Copyright (c) 2002-2004 Judd Vinet <jvinet@zeroflux.org> and is
licensed through the GNU General Public License (see COPYING).
The following options also have `alpm_option_{add,remove}_*` functions, as the
values are list structures.
NOTE: The add and remove functions are NOT plural, as they are in English:
alpm_option_{get,set}_noupgrades -> alpm_option_{add,remove}_noupgrade.
pacman uses "libtar", a library for reading/writing tar-files. This
library is Copyright (c) 1998-2001 Mark D. Roth <roth@uiuc.edu> (see
libtar-X.X.X/COPYRIGHT for furthur details).
* cachedirs: Paths to pacman's download caches (Default: /var/cache/pacman/pkg)
* noupgrades: Files which will never be touched by pacman (extracted as .pacnew)
* noextracts: Files which will never be extracted at all (no .pacnew file)
* ignorepkgs: Packages to ignore when upgrading.
* ignoregrps: Groups to ignore when upgrading.
pacman uses "ftplib", a library for sending/receiving files via FTP. This
library is copyright (c) 1996-2000 Thomas Pfau, pfau@cnj.digex.net (see
libftp/ftplib.c for furthur details).
The following options are read-only, having ONLY alpm_option_get_* functions:
* root: The root directory for pacman to install to
* dbpath: The toplevel database directory
* lockfile: The file used for locking the database (Default: <dbpath>/db.lck)
[Transactions]
The transaction structure permits easy manipulations of several packages
at a time (i.e. adding, upgrade and removal operations).
A transaction can be initiated with a type (SYNC, 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 already installed packages (dependency checking, etc...)
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 checking, 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.
[Package Cache]
libalpm maintains two caches for each DB. One is a general package cache, the
other is a group cache (for package groups). These caches are loaded on demand,
and freed when the library is.
It is important to note that, as a general rule, package structures should NOT
be freed manually, as they SHOULD be part of the cache. The cache of a
database is always updated by the library after an operation changing the
database content (adding and/or removal of packages). Beware frontends ;)
[Package]
The package structure maintains all information for a package. In general,
packages should never be freed from front-ends, as they should always be part
of the package cache.
The 'origin' data member indicates whether the package is from a file (i.e. -U
operations) or from the package cache. In the case of a file, all data members
available are present in the structure. Packages indicated as being from the
cache have data members filled on demand. For this reason, the alpm_pkg_get_*
functions will load the data from the DB as needed.
[Errors]
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, -1 indicating a failure.
If -1 is returned, the variable pm_errno is set to a meaningful value
Wise frontends should always care for these returned values.
Note: the helper function alpm_strerror() can also be used to translate one
specified error code into a more friendly sentence, and alpm_strerrorlast()
does the same for the last error encountered (represented by pm_errno).
[List - alpm_list_t]
The alpm_list_t structure is a doubly-linked list for use with the libalpm
routines. This type is provided publicly so that frontends are free to use it
if they have no native list type (C++, glib, python, etc all have list types).
See the proper man pages for alpm_list_t references.
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
dummy 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_initialize(), and alpm_release().
Read the configuration file, and parse command line arguments.
Based on the action requested, it initiates the appropriate transactions
(see pacman_upgrade(), pacman_remove(), pacman_sync() in files upgrade.c,
remove.c and sync.c).
[CONFIGURATION] (see conf.h)
The frontend is using a configuration file, usually "/etc/pacman.conf". Some
of these options are only useful for the frontend only (mainly the ones used to
control the output like verbosepkglist, or the behavior with cleanmethod).
The rest is used to configure the library.
[UPGRADE/REMOVE/SYNC]
The file pacman.c has been divided into several smaller files, namely
upgrade.c, remove.c, sync.c and query.c, to hold the big parts: pacman_upgrade,
pacman_remove, pacman_sync.
These 3 functions have been split to ease the code reading.
API CHANGES BETWEEN 3.1 AND 3.2
===============================
[REMOVED]
- alpm_db_whatprovides()
- alpm_splitdep (no longer public)
- trans->targets was removed, so alpm_trans_get_targets() as well
- error codes:
PM_ERR_OPT_*, PM_ERR_PKG_INSTALLED, PM_ERR_DLT_CORRUPTED,
PM_ERR_LIBARCHIVE_ERROR
- event: PM_TRANS_EVT_EXTRACT_DONE
- PM_TRANS_TYPE_ADD pmtranstype_t (add transaction)
- PM_TRANS_FLAG_DEPENDSONLY pmtransflag_t
[CHANGED]
- alpm_grp_get_pkgs returns with pmpkg_t list, not package-name list
- Swap parameters on PM_TRANS_CONV_INSTALL_IGNOREPKG callback function
- download callback API changed: alpm_cb_download, alpm_cb_totaldl split
(+ new alpm_option_get_totaldlcb(), alpm_option_set_totaldlcb() functions)
- unsigned long->off_t changes where size is used
- pmsyncpkg_t struct changes:
- pmsynctype_t and alpm_sync_get_type() were removed
- alpm_sync_get_data() was removed
- alpm_sync_get_removes() was added
[ADDED]
- alpm_delta_get_from_md5sum(), alpm_delta_get_to_md5sum()
- alpm_miss_get_causingpkg() (new causingpkg field in pmdepmissing_t)
- alpm_checkdbconflicts()
- alpm_sync_newversion()
- alpm_deptest()
- error codes:
PM_ERR_DLT_INVALID, PM_ERR_LIBARCHIVE, PM_ERR_LIBDOWNLOAD and
PM_ERR_EXTERNAL_DOWNLOAD
- flags:
PM_TRANS_FLAG_ALLEXPLICIT, PM_TRANS_FLAG_UNNEEDED and
PM_TRANS_FLAG_RECURSEALL
API CHANGES BETWEEN 3.2 AND 3.3
===============================
[REMOVED]
- pmsyncpkg_t struct (pmpkg_t is used for all types of transaction targets):
- alpm_sync_get_pkg()
- alpm_sync_get_removes() (use alpm_pkg_get_removes() instead)
- HoldPkg handling (it is the front-end's task):
- alpm_option_get_holdpkgs()
- alpm_option_add_holdpkg()
- alpm_option_set_holdpkgs()
- alpm_option_remove_holdpkg()
- PM_TRANS_CONV_REMOVE_HOLDPKG conversation
- Print URIs feature (it is the front-end's task):
- flag: PM_TRANS_FLAG_PRINTURIS
- event: PM_TRANS_EVT_PRINTURI
- alpm_delta_get_from_md5sum() and alpm_delta_get_to_md5sum()
- alpm_sync_sysupgrade()
- error codes:
PM_ERR_TRANS_COMMITING, PM_ERR_TRANS_DOWNLOADING, PM_ERR_PKG_LOAD,
PM_ERR_PKG_CANT_FRESH, PM_ERR_GRP_NOT_FOUND, PM_ERR_USER_ABORT,
PM_ERR_INTERNAL_ERROR, PM_ERR_DB_SYNC, PM_ERR_PKG_HOLD and
PM_ERR_LIBDOWNLOAD
[CHANGED]
- XferCommand support was removed, any fetch callback function can be defined:
- alpm_option_get_xfercommand() and alpm_option_set_xfercommand() were removed
- alpm_option_get_fetchcb() and alpm_option_set_fetchcb() were added
- function renames:
- alpm_db_getpkgcache() -> alpm_db_get_pkgcache()
- alpm_db_getgrpcache() -> alpm_db_get_grpcache()
- alpm_dep_get_string() -> alpm_dep_compute_string()
- alpm_get_md5sum() -> alpm_compute_md5sum()
- alpm_checkdbconflicts() -> alpm_checkconflicts()
- alpm_trans_sysupgrade() has a new enable_downgrade parameter
- alpm_checkdeps() and alpm_checkconflicts() require local package list instead
of local database
- the to-be-upgraded package is passed to the callback function with
PM_TRANS_EVT_UPGRADE_START (as the second parameter)
- the "requiredby" package is never passed to the callback function with
PM_TRANS_CONV_INSTALL_IGNOREPKG (the second parameter is always NULL)
[ADDED]
- alpm_pkg_get_db()
- alpm_pkg_get_removes()
- conversation: PM_TRANS_CONV_REMOVE_PKGS (remove unresolvable targets)
- flag: PM_TRANS_FLAG_NOLOCK (do not lock database)
- error codes:
PM_ERR_SERVER_NONE, PM_ERR_TRANS_NOT_LOCKED, PM_ERR_PKG_IGNORED and
PM_ERR_LIBFETCH
API CHANGES BETWEEN 3.3 AND 3.4
===============================
[REMOVED]
- pmtranstype_t struct (transaction type), alpm_trans_get_type()
- alpm_option_get_nopassiveftp(), alpm_option_set_nopassiveftp()
[CHANGED]
- interface for target loading:
- alpm_trans_addtarget() and alpm_trans_sysupgrade() were removed
- alpm_sync_target() and alpm_sync_dbtarget() can be used to add a sync target
- alpm_sync_sysupgrade() can be used to add outdated packages (for sysupgrade)
- alpm_add_target() can be used to add an add/upgrade target
- alpm_remove_target() can be used to add a remove target
- interface for target listing:
- alpm_trans_get_pkgs() was removed
- alpm_pkg_get_removes() was removed
- alpm_trans_get_add() can be used to list add/upgrade/sync targets
- alpm_trans_get_remove() can be used to list to-be-removed packages
- the type parameter of alpm_trans_init() was removed
- the type of alpm_db_fetch callback function: mtimeold and mtimenew parameters
were replaced by force parameter
- unsigned short -> int changes for Boolean variables
[ADDED]
- alpm_db_set_pkgreason()
- alpm_option_get_arch(), alpm_option_set_arch()
- alpm_option_get_usedelta()
- alpm_pkg_unused_deltas()
- alpm_conflict_get_reason()
- error code: PM_ERR_PKG_INVALID_ARCH
API CHANGES BETWEEN 3.4 AND 3.5
===============================
[REMOVED]
- alpm_db_register_local()
- alpm_pkg_has_force()
- alpm_depcmp()
[CHANGED]
- alpm_trans_cb_progress type had some types changed from int to size_t
- alpm_cb_log format string is now const char *
- the interface to add/remove targets:
- functions take pmpkg_t * rather than char *.
- alpm_sync_target() and alpm_sync_dbtarget() are replaced by alpm_add_pkg()
- alpm_add_target() is replaced by alpm_add_pkg()
- alpm_remove_target() is replaced by alpm_remove_pkg()
- packages can come from:
- alpm_db_get_pkg() for normal targets
- alpm_find_dbs_satisfier() for versioned provisions
- alpm_find_grp_pkgs() for groups
- alpm_deptest() is replaced by the more flexible alpm_find_satisfier()
- size_t used for alpm_list_t sizes
- return type for alpm_list_count()
- parameter type in alpm_list_msort() and alpm_list_nth()
[ADDED]
- alpm_option_get_checkspace(), alpm_option_set_checkspace()
- alpm_find_grp_pkgs()
- alpm_trans_get_flags()
- error codes:
PM_ERR_DISK_SPACE, PM_ERR_WRITE
- flags:
PM_TRANS_FLAG_NODEPVERSION, PM_TRANS_EVT_DISKSPACE_START,
PM_TRANS_EVT_DISKSPACE_DONE, PM_TRANS_CONV_SELECT_PROVIDER,
PM_TRANS_PROGRESS_DISKSPACE_START, PM_TRANS_PROGRESS_INTEGRITY_START
API CHANGES BETWEEN 3.5 AND 4.0
===============================
[REMOVED]
- error codes:
PM_ERR_LIBFETCH, PM_ERR_WRITE
- alpm_option_set_root(), alpm_option_set_dbpath()
- alpm_list_first()
- alpm_grp_get_name(), alpm_grp_get_pkgs()
- alpm_delta_get_from(), alpm_delta_get_to(), alpm_delta_get_filename(),
alpm_delta_get_md5sum(), alpm_delta_get_size()
- alpm_miss_get_target(), alpm_miss_get_dep(), alpm_miss_get_causingpkg()
- alpm_dep_get_mod(), alpm_dep_get_name(), alpm_dep_get_version()
- alpm_conflict_get_package1(), alpm_conflict_get_package2(),
alpm_conflict_get_reason()
- alpm_fileconflict_get_target(), alpm_fileconflict_get_type(),
alpm_fileconflict_get_file(), alpm_fileconflict_get_ctarget()
- alpm_db_get_url()
[CHANGED]
- PM_ prefixes for enum values are now ALPM_
- pm prefixes for structs and enums are now alpm_
- alpm_initialize now has parameters: char *root, char *dbpath,
alpm_errno_t *err and returns an alpm_handle_t struct.
- alpm_release now takes an alpm_handle_t *.
- alpm_db_register_sync() now requires a extra parameter of a alpm_siglevel_t.
- alpm_pkg_load() now requires an extra parameter of an alpm_siglevel_t
- alpm_db_setserver() replaced by alpm_db_set_servers(), alpm_db_add_server(),
alpm_db_remove_server()
- alpm_trans_init() no longer takes callbacks, set those using
alpm_option_set_*cb() functions
- many functions now require a first parameter of an alpm_handle_t *:
- alpm_option_get_*
- alpm_option_set_*
- alpm_option_add_*
- alpm_option_remove_*
- alpm_trans_*
- alpm_add_pkg
- alpm_checkconflicts
- alpm_checkdeps
- alpm_db_register_sync
- alpm_db_set_pkgreason
- alpm_db_unregister_all
- alpm_fetch_pkgurl
- alpm_find_dbs_satisfier
- alpm_logaction
- alpm_pkg_load
- alpm_release
- alpm_remove_pkg
- alpm_sync_sysupgrade
- several structs are no longer opaque:
- alpm_conflict_t
- alpm_delta_t
- alpm_depend_t
- alpm_depmissing_t
- alpm_depmod_t
- alpm_fileconflict_t
- alpm_group_t
- alpm_pkg_reason_t
[ADDED]
- option functions:
- alpm_{get,set}_eventcb()
- alpm_option_{get,set}_convcb()
- alpm_option_{get,set}_progresscb()
- package signing functions:
- alpm_option_get_default_siglevel()
- alpm_option_set_default_siglevel()
- alpm_option_get_gpgdir()
- alpm_option_set_gpgdir()
- alpm_db_get_siglevel()
- alpm_siglist_cleanup()
- alpm_db_check_pgp_signature()
- alpm_pkg_check_pgp_signature()
- alpm_pkg_get_origin()
- alpm_pkg_get_sha256sum()
- alpm_pkg_get_base64_sig()
- list functions:
- alpm_list_to_array()
- alpm_list_previous()
- structs:
- alpm_backup_t
- alpm_file_t
- alpm_filelist_t
- enums:
- alpm_siglevel_t
- alpm_sigstatus_t
- alpm_sigvalidity_t
- alpm_pkgfrom_t
- error codes:
ALPM_ERR_DB_INVALID, ALPM_ERR_DB_INVALID_SIG, ALPM_ERR_GPGME,
ALPM_ERR_PKG_INVALID_CHECKSUM, ALPM_ERR_PKG_INVALID_SIG, ALPM_ERR_SIG_INVALID,
ALPM_ERR_SIG_MISSING
API CHANGES BETWEEN 4.0 AND 4.1
===============================
[REMOVED]
- alpm_list_getdata()
[CHANGED]
- alpm_pkgfrom_t members are now prefixed with ALPM_
- alpm_siglevel_t - added members ALPM_SIG_PACKAGE_SET, ALPM_SIG_PACKAGE_TRUST_SET
- alpm_depend_t - additional desc member
- alpm_filelist_t - additional resolved_path member
- alpm_pgpkey_t - added members length, revoked, pubkey_algo
- alpm_logaction - added caller identifier argument
- function renaming:
- alpm_option_get_localdb -> alpm_get_localdb
- alpm_option_get_syncdbs -> alpm_get_syncdbs
- alpm_db_register_sync -> alpm_register_syncdb
- alpm_db_unregister_all -> alpm_unregister_all_syncdbs
- alpm_db_readgroup -> alpm_db_get_group
- alpm_db_set_pkgreason -> alpm_pkg_set_reason (handle parameter removed)
- alpm_time_t typedef used for all times:
- members of alpm_pgpkey_t
- return types of alpm_pkg_get_builddate and alpm_pkg_get_installdate
- delta options now use required ratio rather than on/off:
- alpm_option_get_usedelta -> alpm_option_get_deltaratio
- alpm_option_set_usedelta -> alpm_option_set_deltaratio
[ADDED]
- tracking of how a package was validated:
- alpm_pkgvalidation_t
- alpm_pkg_get_validation()
- adjustable signature verification levels for upgrade operations:
- alpm_option_get_local_file_siglevel()
- alpm_option_set_local_file_siglevel()
- alpm_option_get_remote_file_siglevel()
- alpm_option_set_remote_file_siglevel()
- sync database usage functions:
- alpm_db_usage_t
- alpm_db_set_usage()
- alpm_db_get_usage()
- wrapper functions for reading mtree files:
- alpm_pkg_mtree_open()
- alpm_pkg_mtree_next()
- alpm_pkg_mtree_close()
- utility functions:
- alpm_pkg_find()
- alpm_pkg_compute_optionalfor()
- alpm_filelist_contains()
- types:
- alpm_time_t
- alpm_errno_t
- flags:
ALPM_EVENT_OPTDEP_REQUIRED, ALPM_EVENT_DATABASE_MISSING,
ALPM_EVENT_KEYRING_START, ALPM_EVENT_KEYRING_DONE, ALPM_EVENT_KEY_DOWNLOAD_START,
ALPM_EVENT_KEY_DOWNLOAD_DONE, ALPM_PROGRESS_KEYRING_START
API CHANGES BETWEEN 4.1 AND 4.2
===============================
[CHANGED]
- alpm_filelist_t - removed member resolved_path
- alpm_filelist_contains - now returns alpm_file_t
- event callback:
- alpm_event_t renamed to alpm_event_type_t
- alpm_event_t union added
- alpm_event_cb now takes only an alpm_event_t parameter
- alpm_event_any_t, alpm_package_operation_t, alpm_event_package_operation_t,
alpm_event_optdep_removal_t, alpm_event_delta_patch_t, alpm_event_scriptlet_info_t,
alpm_event_database_missing_t, alpm_event_pkgdownload_t, alpm_event_pacnew_created_t,
alpm_event_pacsave_created_t, alpm_event_pacorig_created_t added
- ALPM_EVENT_*_START -> ALPM_EVENT_PACKAGE_OPERATION_START
- ALPM_EVENT_*_DONE -> ALPM_EVENT_PACKAGE_OPERATION_DONE
- question callback:
- alpm_question_t renamed to alpm_question_type_t
- alpm_question_t union added
- alpm_cb_question now takes only an alpm_question_t parameter
- alpm_question_any_t, alpm_question_install_ignorepkg_t, alpm_question_replace_t
alpm_question_conflict_t, alpm_question_corrupted_t, alpm_question_remove_pkgs_t,
alpm_question_select_provider_t, alpm_question_import_key_t added
[ADDED]
- memory management:
- alpm_fileconflict_free()
- alpm_depmissing_free()
- alpm_conflict_free()
- alpm_dep_free()
- database usage:
- alpm_db_usage_t
- alpm_db_set_usage()
- alpm_db_get_usage()
- assume installed:
- alpm_option_get_assumeinstalled()
- alpm_option_add_assumeinstalled()
- alpm_option_set_assumeinstalled()
- alpm_option_remove_assumeinstalled()
- using noupgrade/noextract:
- alpm_option_match_noupgrade()
- alpm_option_match_noextract()
- utility functions:
- alpm_dep_from_string()
- alpm_pkg_should_ignore()
- alpm_decode_signature()
- alpm_extract_keyid()
- flags:
ALPM_EVENT_RETRIEVE_DONE, ALPM_EVENT_RETRIEVE_FAILED, ALPM_EVENT_PKGDOWNLOAD_START,
ALPM_EVENT_PKGDOWNLOAD_DONE, ALPM_EVENT_PKGDOWNLOAD_FAILED, ALPM_EVENT_OPTDEP_REMOVAL,
ALPM_EVENT_PACNEW_CREATED, ALPM_EVENT_PACSVAE_CREATED, ALPM_EVENT_PACORIG_CREATED
API CHANGES BETWEEN 4.2 AND 5.0
===============================
[REMOVED]
- alpm_siglevel_t - removed members ALPM_SIG_PACKAGE_SET, ALPM_SIG_PACKAGE_TRUST_SET
- removed .pacorig generation:
- ALPM_EVENT_PACORIG_CREATED
- alpm_event_pacorig_created_t
- alpm_event_t.pacorig_created
[ADDED]
- hook support:
- alpm_option_get_hookdirs()
- alpm_option_set_hookdirs()
- alpm_option_add_hookdir()
- alpm_option_remove_hookdir()
- alpm_event_hook_t, alpm_event_hook_run_t
- alpm_hook_when_t
- ALPM_EVENT_HOOK_START, ALPM_EVENT_HOOK_DONE
- ALPM_EVENT_HOOK_RUN_START, ALPM_EVENT_HOOK_RUN_DONE
- ALPM_ERR_TRANS_HOOK_FAILED
- different database extension support:
- alpm_option_get_dbext()
- alpm_option_set_dbext()
- pkgbase accessor:
- alpm_pkg_get_base()
- transaction events:
- ALPM_EVENT_TRANSACTION_START, ALPM_EVENT_TRANSACTION_DONE
- database unlocking:
- alpm_unlock()
API CHANGES BETWEEN 5.0 AND 5.1
===============================
[CHANGED]
- alpm_errno_t - added member ALPM_ERR_OK
- alpm_siglevel_t - value of ALPM_SIG_USE_DEFAULT changed
- functions using bitfields return/pass an int instead of an enum:
- alpm_option_get_default_siglevel()
- alpm_option_set_default_siglevel()
- alpm_option_get_remote_file_siglevel()
- alpm_option_set_remote_file_siglevel()
- alpm_register_syncdb()
- alpm_db_get_siglevel()
- alpm_db_set_usage()
- alpm_db_get_usage()
- alpm_pkg_load()
- alpm_pkg_get_validation()
- alpm_trans_get_flags()
- alpm_trans_init()
- alpm_option_get_local_file_siglevel()
- alpm_option_set_local_file_siglevel()
[ADDED]
- overwrite support:
- alpm_option_get_overwrite_files()
- alpm_option_set_overwrite_files()
- alpm_option_add_overwrite_file()
- alpm_option_remove_overwrite_file()
- download timeout control:
- alpm_option_set_disable_dl_timeout()
- access make/checkdepends info:
- alpm_pkg_get_checkdepends()
- alpm_pkg_get_makedepends()
- check pacman capabilities:
- alpm_capabilities()
- duplicate and add to list:
- alpm_list_append_strdup()
API CHANGES BETWEEN 5.1 AND 5.2
===============================
[REMOVED]
- package delta support:
- alpm_delta_t
- alpm_event_delta_patch_t
- alpm_event_t union - removed alpm_event_delta_patch_t
- ALPM_EVENT_DELTA_INTEGRITY_START, ALPM_EVENT_DELTA_INTEGRITY_DONE,
ALPM_EVENT_DELTA_PATCHES_START, ALPM_EVENT_DELTA_PATCHES_DONE,
ALPM_EVENT_DELTA_PATCH_START, ALPM_EVENT_DELTA_PATCH_DONE,
ALPM_EVENT_DELTA_PATCH_FAILED
- ALPM_ERR_DLT_INVALID, ALPM_ERR_DLT_PATCHFAILED
- alpm_option_get_deltaratio()
- alpm_option_set_deltaratio()
- alpm_pkg_get_deltas()
- alpm_pkg_unused_deltas()
- alpm_transflag_t - removed member ALPM_TRANS_FLAG_FORCE
[CHANGED]
- alpm_errno_t - added member ALPM_ERR_MISSING_CAPABILITY_SIGNATURES
- alpm_sync_newversion() replaced with alpm_sync_get_new_version() which
does not filter on any ALPM_DB_USAGE_*.
API CHANGES BETWEEN 5.2 AND 6.0
===============================
[REMOVED]
- ALPM_EVENT_PKGDOWNLOAD_START, ALPM_EVENT_PKGDOWNLOAD_DONE, ALPM_EVENT_PKGDOWNLOAD_FAILED
- ALPM_ERR_PKG_REPO_NOT_FOUND
- old TotalDownload implementation:
- alpm_cb_totaldl
- alpm_option_get_totaldlcb()
- alpm_option_set_totaldlcb()
[CHANGED]
- alpm_db_update() now accepts a list of databases rather than a single database.
- alpm_fetch_pkgurl() accepts a list of packages to download.
- alpm_db_search() now has an additional parameter and returns success status
- ALPM_EVENT_RETRIEVE_* -> ALPM_EVENT_DB_RETRIEVE_* and ALPM_EVENT_PKG_RETRIEVE_*
- alpm_cb_download pass event and data
- multi architecture support:
- alpm_option_get_arch() -> alpm_option_get_architectures()
- alpm_option_set_arch() -> alpm_option_set_architectures()
- alpm_db_get_servers() copies parameter data
[ADDED]
- parallel download support:
- alpm_option_set_parallel_downloads()
- alpm_option_get_parallel_downloads()
- file download events:
- alpm_download_event_type_t
- alpm_download_event_init_t
- alpm_download_event_progress_t
- alpm_download_event_completed_t
- download misc:
- ALPM_DOWNLOAD_RETRY
- alpm_download_event_retry_t
- alpm_event_pkg_retrieve_t
- multiarchitecture support:
- alpm_option_add_architecture()
- alpm_option_remove_architecture()
- misc:
- alpm_pkg_get_sig()
- callbacks add front-end provided context
API CHANGES BETWEEN 6.0 AND 6.1
===============================
[REMOVED]
- alpm_trans_t
[CHANGED]
- alpm_conflict_t - full package added as member, removing package name and name
hash members
- alpm_question_import_key_t - holds key uid and fingerprint rather than alpm_pgpkey_t
- alpm_pkgreason_t - added ALPM_PKG_REASON_UNKNOWN
- alpm_transflag_t - added ALPM_TRANS_FLAG_NOHOOKS
[ADDED]
- extensible package data type:
- alpm_pkg_xdata_t
- alpm_pkg_get_xdata()
- accessor functions:
- alpm_db_get_handle()
- alpm_pkg_get_handle()
- cache server support:
- alpm_db_get_cache_servers()
- alpm_db_set_cache_servers()
- alpm_db_add_cache_server()
API CHANGES BETWEEN 6.1 AND 7.0
===============================
[ADDED]
- sandbox functions:
- alpm_option_get_sandboxuser()
- alpm_option_set_sandboxuser()
- alpm_option_set_disable_sandbox()
- alpm_sandbox_setup_child()
API CHANGES BETWEEN 7.0 AND 7.1
===============================
[CHANGED]
- error codes:
PM_ERR_TRANS_COMMITING renamed to PM_ERR_TRANS_COMMITTING

34
RELEASE
View file

@ -1,34 +0,0 @@
The following checklist should be used for making a pacman release.
- Ensure "ninja dist" succeeds
- Call a freeze to development.
- Send translation updates to Transifex at least two weeks before a major
release (see below). At this stage, strings can only be changed for a
major issue.
- Update NEWS and README files
- Pull translation updates from Transifex
- Update version in meson.build as described in file
- Update doc/index.asciidoc
- Create a signed git tag (git tag -s vX.Y.Z -m "commit message")
- Create and sign release tarballs (generate with "ninja dist")
- Create release on gitlab project page
- Upload release tarball and signature to gitlab ("glab release upload ...")
- Create branch release/?.?.x (with ?.? replaced by major version number)
- Update .gitlab-ci.yml to point the website pages run at release branch
Transifex updates are handled using the transifex client. The basic process is:
- Pull updates from transifex ("tx pull -f --minimum-perc 75")
- Update po files ("./build-aux/update-po")
- Fix all translation errors found (e.g. using "mint-check-translations")
- Add any new locales to the relevant LINGUAS file
- Optional: Make any manual changes needed (e.g. fixing spacing in a string)
and update po files again
- Push updated po files to transifex ("tx push -s -t --skip")
Point releases:
- all bugs fixes slated for the release branch must first land on master
(unless no longer relevant)
- following the initial post-release period when the release and master
branches may be kept in sync, commits are backported to the release branch
using "git cherry-pick -x"
- translation updates should be pulled onto the release branch only

View file

@ -1,60 +0,0 @@
Thanks to all of those who have helped translate pacman, both in the past and
currently. Our translations are currently maintained in Transifex; please read
doc/translation-help.txt for more details.
Below is a list of past translators before we switched to Transifex; more can
be found by looking in the Git history.
If your language is not already in the various po/ subdirectories and you wish
it was, set up a team in Transifex for your language and we will be happy to
add your language to the mix.
Catalan (ca):
Manuel Tortosa <manutortosa@chakra-project.org>
Czech (cs):
Vojtěch Gondžala <vojtech.gondzala@gmail.com>
German (de):
Matthias Gorissen <matthias@archlinux.de>
Greek (el):
Christos Nouskas <nouskas@gmail.com>
British English (en_GB):
Jeff Bailes <thepizzaking@gmail.com>
Spanish (es):
Juan Pablo González Tognarelli <lord_jotape@yahoo.com.ar>
Fernando Lagos <fernando@zerial.org>
French (fr):
Chantry Xavier <shiningxc@gmail.com>
Hungarian (hu):
Nagy Gabor <ngaba@bibl.u-szeged.hu>
Avramucz Péter <muczyjoe@gmail.com>
Italian (it):
Giovanni Scafora <giovanni@archlinux.org>
Kazakh (kk):
Baurzhan Muftakhidinov <baurthefirst@gmail.com>
Norwegian (nb):
Hans-Kristian Arntzen <maister@archlinux.us>
Polish (pl):
Mateusz Herych <heniekk@gmail.com>
Jaroslaw Swierczynski <swiergot@gmail.com>
Mateusz Jędrasik <m.jedrasik@gmail.com>
Brazilian Portuguese (pt_BR):
Armando M. Baratti <ambaratti@archlinux-br.org>
Rodrigo Flores <flores@archlinux-br.org>
Marcelo Cavalcante <kalibslack@gmail.com>
Romanian (ro):
Volodia Macovei <blog@volodia.ro>
Russian (ru):
Sergey Tereschenko <serg.partizan@gmail.com>
Vitaly Dolgov <ferhiord@gmail.com>
Oleg Finkelshteyn <olegfink@gmail.com>
Vladimir Bayrakovskiy <4rayven@gmail.com>
Swedish (sv):
Christian Larsson <congacx@gmail.com>
Turkish (tr):
Samed Beyribey <ras0ir@eventualis.org>
Alper KANAT <alperkanat@gmail.com>
Ukrainian (uk):
Roman Kyrylych (Роман Кирилич) <roman.kyrylych@gmail.com>
Ivan Kovnatsky (Іван Ковнацький) <sevenfourk@gmail.com>
Simplified Chinese (zh_CN):
甘露(Lu.Gan) <rhythm.gan@gmail.com>

View file

@ -1,2 +0,0 @@
*
!ltmain-asneeded.patch

View file

@ -1,11 +0,0 @@
#!/usr/bin/python3
import sys
for path in sys.argv[1:]:
print('# -----------------------------------')
print('# ' + path + ':')
print('# -----------------------------------')
with open(path, 'r') as f:
for line in f:
print('# ' + line, end='')

View file

@ -1,29 +0,0 @@
#!@BASH@
input=$1
output=$2
mode=$3
sed \
-e "s|@rootdir[@]|@ROOTDIR@|g" \
-e "s|@localedir[@]|@LOCALEDIR@|g" \
-e "s|@sysconfdir[@]|@sysconfdir@|g" \
-e "s|@localstatedir[@]|@localstatedir@|g" \
-e "s|@libmakepkgdir[@]|@LIBMAKEPKGDIR@|g" \
-e "s|@pkgdatadir[@]|@PKGDATADIR@|g" \
-e "s|@keyringdir[@]|@KEYRINGDIR@|g" \
-e "s|@prefix[@]|@PREFIX@|g" \
-e "1s|#!/bin/bash|#!@BASH@|g" \
-e "s|@PACKAGE_VERSION[@]|@PACKAGE_VERSION@|g" \
-e "s|@PACKAGE_NAME[@]|@PACKAGE_NAME@|g" \
-e "s|@BUILDSCRIPT[@]|@BUILDSCRIPT@|g" \
-e "s|@TEMPLATE_DIR[@]|@TEMPLATE_DIR@|g" \
-e "s|@DEBUGSUFFIX[@]|@DEBUGSUFFIX@|g" \
-e "s|@INODECMD[@]|@INODECMD@|g" \
-e "s|@FILECMD[@]|@FILECMD@|g" \
-e "s|@BSDTAR_NO_READ_SPARSE[@]|@BSDTAR_NO_READ_SPARSE@|g" \
"$input" >"$output"
if [[ $mode ]]; then
chmod "$mode" "$output"
fi

View file

@ -1,10 +0,0 @@
#!/bin/sh
set -eu
# this is needed mostly because $DESTDIR is provided as a variable,
# and we need to create the target directory...
mkdir -vp "$(dirname "${DESTDIR:-}$2")"
rm -f "${DESTDIR:-}$2"
ln -vs "$1" "${DESTDIR:-}$2"

View file

@ -1,17 +0,0 @@
#!/usr/bin/python
import json
import sys
def print_result(result):
print('==================================================================')
print(result['name'])
print(' '.join(result['command']))
print('==================================================================')
print(result['stdout'])
with open(sys.argv[1], 'r') as f:
for line in f:
result = json.loads(line)
if result['result'] == 'FAIL':
print_result(result)

View file

@ -1,6 +0,0 @@
#!/bin/bash
# This script serves as a trampoline for running scripts which depend on
# libmakepkg with the libmakepkg within the build tree.
MAKEPKG_LIBRARY=@BUILDDIR@/libmakepkg exec @BASH@ -$- @REAL_PROGPATH@ "$@"

View file

@ -1,8 +0,0 @@
#! /bin/sh
OLD=$1
NEW=$2
for file in $(git grep -l "Copyright .* Pacman Development" | grep -v "\.po"); do \
sed -i -e "/Copyright (/s/-${OLD}/-${NEW}/" -e "/Copyright (/s/ ${OLD}/ ${OLD}-${NEW}/" "$file"
done

View file

@ -1,39 +0,0 @@
#!/bin/bash
find_build_directory() {
local build_dirs=(*/build.ninja)
if [[ ! -e ${build_dirs[0]} ]]; then
echo "error: No build directory found. Have you run 'meson build' yet?" >&2
return 1
elif (( ${#build_dirs[*]} > 1 )); then
echo "error: Multiple build directories found. Unable to proceed." >&2
return 1
fi
printf '%s\n' "${build_dirs[0]%/*}"
}
filter_targets_by_name() {
if command -v jq &>/dev/null; then
jq --arg re "$1" -r 'map(.name)[] | select(match($re))'
else
json_pp | awk -v filter="$1" -F'[:"]' \
'$2 == "name" && $(NF - 1) ~ filter { print $(NF - 1) }'
fi
}
# Make things simple and require that we're in the build root rather than
# trying to chase down the location of this script and the relative build dir.
if [[ ! -d .git ]]; then
echo "This script must be run from the root of the repository" >&2
exit 1
fi
build_dir=$(find_build_directory) || exit 1
mapfile -t targets < \
<(meson introspect "$build_dir" --targets | filter_targets_by_name "-update-po$")
ninja -C "$build_dir" "${targets[@]}"

1321
config.guess vendored Executable file

File diff suppressed because it is too large Load diff

157
config.h.in Normal file
View file

@ -0,0 +1,157 @@
/* config.h.in. Generated from configure.in by autoheader. */
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
systems. This function is required for `alloca.c' support on those systems.
*/
#undef CRAY_STACKSEG_END
/* Define to 1 if using `alloca.c'. */
#undef C_ALLOCA
/* Define to 1 if you have `alloca', as a function or macro. */
#undef HAVE_ALLOCA
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
*/
#undef HAVE_ALLOCA_H
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
*/
#undef HAVE_DIRENT_H
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
#undef HAVE_DOPRNT
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the `getpass' function. */
#undef HAVE_GETPASS
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `z' library (-lz). */
#undef HAVE_LIBZ
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define to 1 if `lstat' has the bug that it succeeds when given the
zero-length file name argument. */
#undef HAVE_LSTAT_EMPTY_STRING_BUG
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#undef HAVE_MALLOC
/* Define to 1 if you have the `memmove' function. */
#undef HAVE_MEMMOVE
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `mkdir' function. */
#undef HAVE_MKDIR
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
#undef HAVE_NDIR_H
/* Define to 1 if you have the `realpath' function. */
#undef HAVE_REALPATH
/* Define to 1 if you have the `rmdir' function. */
#undef HAVE_RMDIR
/* Define to 1 if `stat' has the bug that it succeeds when given the
zero-length file name argument. */
#undef HAVE_STAT_EMPTY_STRING_BUG
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strdup' function. */
#undef HAVE_STRDUP
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strstr' function. */
#undef HAVE_STRSTR
/* Define to 1 if you have the `strverscmp' function. */
#undef HAVE_STRVERSCMP
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
*/
#undef HAVE_SYS_DIR_H
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
*/
#undef HAVE_SYS_NDIR_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `vprintf' function. */
#undef HAVE_VPRINTF
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define as the return type of signal handlers (`int' or `void'). */
#undef RETSIGTYPE
/* If using the C implementation of alloca, define if you know the
direction of stack growth for your system; otherwise it will be
automatically deduced at run-time.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown */
#undef STACK_DIRECTION
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to rpl_malloc if the replacement function should be used. */
#undef malloc
/* Define to `int' if <sys/types.h> does not define. */
#undef mode_t
/* Define to `unsigned' if <sys/types.h> does not define. */
#undef size_t

1443
config.sub vendored Executable file

File diff suppressed because it is too large Load diff

6438
configure vendored Executable file

File diff suppressed because it is too large Load diff

46
configure.in Normal file
View file

@ -0,0 +1,46 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.57)
AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
AC_CONFIG_SRCDIR([config.h.in])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_PROG_CXX
# Checks for libraries.
AC_CHECK_LIB([c], [printf], , AC_MSG_ERROR([your libc is broken!]))
AC_CHECK_LIB([tar], [tar_open], , AC_MSG_ERROR([missing libtar]))
AC_CHECK_LIB([z], [gzread], , AC_MSG_ERROR([missing zlib]))
# Checks for header files.
AC_HEADER_DIRENT
AC_HEADER_STDC
AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h sys/time.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_MODE_T
AC_TYPE_SIZE_T
AC_HEADER_TIME
AC_TYPE_UID_T
# Checks for library functions.
AC_FUNC_CLOSEDIR_VOID
AC_FUNC_LSTAT
AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_FUNC_SELECT_ARGTYPES
AC_TYPE_SIGNAL
AC_FUNC_STAT
AC_FUNC_VPRINTF
AC_CHECK_FUNCS([gethostbyname memmove memset mkdir realpath rmdir select socket strcasecmp strchr strdup strerror strstr strverscmp])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

9
doc/.gitignore vendored
View file

@ -1,9 +0,0 @@
*.[1-8]
asciidoc-manpage.css
asciidoc.css
asciidoc.js
*.html
*.xml
man3
website.tar.gz
Doxyfile

View file

@ -1,79 +0,0 @@
BUILDINFO(5)
============
Name
----
BUILDINFO - Makepkg package build information file
Synopsis
--------
This manual page describes the format of a BUILDINFO file found in the root of
a package created by makepkg. The file contains a description of the package's
build environment. The information is formatted in key-value pairs separated by
a '=', one value per line. Arrays are represented as multiple key-value pairs
having the same key.
Description
-----------
This is a description of the contents of version '2' of the
BUILDINFO file format.
*format*::
Denotes the file format version, represented by a plain positive integer.
*pkgname*::
The name of the package.
*pkgbase*::
The base name of a package, usually the same as the pkgname except for
split packages.
*pkgver*::
The version of the package including pkgrel and epoch.
*pkgarch*::
The architecture of the package.
*pkgbuild_sha256sum*::
The sha256sum in hex format of the PKGBUILD used to build the package.
*packager*::
The details of the packager that built the package.
*builddate*::
The build date of the package in epoch.
*builddir*::
The directory where the package was built.
*startdir*::
The directory from which makepkg was executed.
*buildtool*::
The name of the tool ecosystem used to set up the build environment. Used
for defining a spec for reproducible builds, e.g. the source of the
linkman:makepkg.conf[5] used.
*buildtoolver*::
The full version of the 'buildtool', for example:
"$pkgver-$pkgrel-$pkgarch".
*buildenv (array)*::
The build environment specified in makepkg.conf.
*options (array)*::
The options set specified when building the package.
*installed (array)*::
The installed packages at build time including the version information of
the package. Formatted as "$pkgname-$pkgver-$pkgrel-$pkgarch".
See Also
--------
linkman:makepkg[8], linkman:pacman[8], linkman:makepkg.conf[5]
include::footer.asciidoc[]

View file

@ -1,342 +0,0 @@
# Doxyfile 1.9.3
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = libalpm
PROJECT_NUMBER =
PROJECT_BRIEF = "Arch Linux Package Manager Library"
PROJECT_LOGO =
OUTPUT_DIRECTORY = @OUTPUT_DIRECTORY@
CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = YES
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = NO
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
JAVADOC_BANNER = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
PYTHON_DOCSTRING = YES
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
OPTIMIZE_OUTPUT_SLICE = NO
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 5
AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
GROUP_NESTED_COMPOUNDS = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = YES
TYPEDEF_HIDES_STRUCT = YES
LOOKUP_CACHE_SIZE = 0
NUM_PROC_THREADS = 1
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_PRIV_VIRTUAL = NO
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
RESOLVE_UNNAMED_PARAMS = YES
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = YES
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
HIDE_COMPOUND_REFERENCE= NO
SHOW_HEADERFILE = YES
SHOW_INCLUDE_FILES = YES
SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_MEMBERS_CTORS_1ST = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_FILES = YES
SHOW_NAMESPACES = YES
FILE_VERSION_FILTER =
LAYOUT_FILE =
CITE_BIB_FILES =
#---------------------------------------------------------------------------
# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_IF_INCOMPLETE_DOC = YES
WARN_NO_PARAMDOC = NO
WARN_AS_ERROR = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = @INPUT_DIRECTORY@/../lib/libalpm/alpm.h \
@INPUT_DIRECTORY@/../lib/libalpm/alpm_list.h
INPUT_ENCODING = UTF-8
FILE_PATTERNS =
RECURSIVE = NO
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXCLUDE_SYMBOLS = _alpm_* \
__alpm_*
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE =
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = NO
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
REFERENCES_LINK_SOURCE = YES
SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = NO
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_DYNAMIC_MENUS = YES
HTML_DYNAMIC_SECTIONS = NO
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_FEEDURL =
DOCSET_BUNDLE_ID = org.doxygen.Project
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_NAME = Publisher
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
CHM_INDEX_ENCODING =
BINARY_TOC = NO
TOC_EXPAND = NO
GENERATE_QHP = NO
QCH_FILE =
QHP_NAMESPACE = org.doxygen.Project
QHP_VIRTUAL_FOLDER = doc
QHP_CUST_FILTER_NAME =
QHP_CUST_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS =
QHG_LOCATION =
GENERATE_ECLIPSEHELP = NO
ECLIPSE_DOC_ID = org.doxygen.Project
DISABLE_INDEX = NO
GENERATE_TREEVIEW = NO
FULL_SIDEBAR = NO
ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
OBFUSCATE_EMAILS = YES
HTML_FORMULA_FORMAT = png
FORMULA_FONTSIZE = 10
FORMULA_MACROFILE =
USE_MATHJAX = NO
MATHJAX_VERSION = MathJax_2
MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH = http://www.mathjax.org/mathjax
MATHJAX_EXTENSIONS =
MATHJAX_CODEFILE =
SEARCHENGINE = NO
SERVER_BASED_SEARCH = NO
EXTERNAL_SEARCH = NO
SEARCHENGINE_URL =
SEARCHDATA_FILE = searchdata.xml
EXTERNAL_SEARCH_ID =
EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
LATEX_MAKEINDEX_CMD = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = letter
EXTRA_PACKAGES =
LATEX_HEADER =
LATEX_FOOTER =
LATEX_EXTRA_STYLESHEET =
LATEX_EXTRA_FILES =
PDF_HYPERLINKS = NO
USE_PDFLATEX = NO
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
LATEX_BIB_STYLE = plain
LATEX_EMOJI_DIRECTORY =
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = YES
MAN_OUTPUT = .
MAN_EXTENSION = .3
MAN_SUBDIR =
MAN_LINKS = NO
#---------------------------------------------------------------------------
# Configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
XML_NS_MEMB_FILE_SCOPE = NO
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
SEARCH_INCLUDES = YES
INCLUDE_PATH = ../..
INCLUDE_FILE_PATTERNS = *.h
PREDEFINED = HAVE_CONFIG_H= \
SYMEXPORT= \
HAVE_LIBARCHIVE \
HAVE_LIBCURL \
HAVE_LIBGPGME
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration options related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
DIA_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
DOT_NUM_THREADS = 0
DOT_FONTPATH =
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
UML_LIMIT_NUM_FIELDS = 10
DOT_UML_DETAILS = NO
DOT_WRAP_THRESHOLD = 17
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DIR_GRAPH_MAX_DEPTH = 1
DOT_IMAGE_FORMAT = png
INTERACTIVE_SVG = NO
DOT_PATH =
DOTFILE_DIRS =
MSCFILE_DIRS =
DIAFILE_DIRS =
PLANTUML_JAR_PATH =
PLANTUML_CFG_FILE =
PLANTUML_INCLUDE_PATH =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 3
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES

View file

@ -1,27 +0,0 @@
# Maintainer: Joe User <joe.user@example.com>
pkgname=patch
pkgver=2.7.1
pkgrel=1
pkgdesc="A utility to apply patch files to original sources"
arch=('i686' 'x86_64')
url="https://www.gnu.org/software/patch/patch.html"
license=('GPL')
groups=('base-devel')
depends=('glibc')
makedepends=('ed')
optdepends=('ed: for "patch -e" functionality')
source=("ftp://ftp.gnu.org/gnu/$pkgname/$pkgname-$pkgver.tar.xz"{,.sig})
sha256sums=('9124ba46db0abd873d0995c2ca880e81252676bb6c03e0a37dfc5f608a9b0ceb'
'SKIP')
build() {
cd "$srcdir/$pkgname-$pkgver"
./configure --prefix=/usr
make
}
package() {
cd "$srcdir/$pkgname-$pkgver"
make DESTDIR="$pkgdir/" install
}

View file

@ -1,544 +0,0 @@
PKGBUILD(5)
===========
Name
----
PKGBUILD - Package build description file
Synopsis
--------
PKGBUILD
Description
-----------
This manual page describes general rules about PKGBUILDs. Once a
PKGBUILD is written, the actual package is built using makepkg and installed
with pacman.
NOTE: An example PKGBUILD, useful for reference, is located in '{pkgdatadir}'
along with other example files such as an install script. You can copy the
provided PKGBUILD.proto file to a new package build directory and make
customizations to suit your needs.
Options and Directives
----------------------
The following is a list of standard options and directives available for use
in a PKGBUILD. These are all understood and interpreted by makepkg, and most
of them will be directly transferred to the built package. The mandatory
fields for a minimally functional PKGBUILD are *pkgname*, *pkgver*, *pkgrel*
and *arch*.
If you need to create any custom variables for use in your build process, it is
recommended to prefix their name with an '_' (underscore).
This will prevent any possible name clashes with internal makepkg variables.
For example, to store the base kernel version in a variable, use something
similar to `$_basekernver`.
*pkgname (array)*::
Either the name of the package or an array of names for split packages.
Valid characters for members of this array are alphanumerics, and any of
the following characters: ```@ . _ + -`''. Additionally, names are not
allowed to start with hyphens or dots.
*pkgver*::
The version of the software as released from the author (e.g., '2.7.1').
The variable is not allowed to contain colons, forward slashes, hyphens
or whitespace.
+
The `pkgver` variable can be automatically updated by providing a `pkgver()`
function in the PKGBUILD that outputs the new package version.
This is run after downloading and extracting the sources and running the
`prepare()` function (if present), so it can use those files in determining the
new `pkgver`. This is most useful when used with sources from version control
systems (see below).
*pkgrel*::
This is the release number specific to the distribution. This
allows package maintainers to make updates to the package's configure
flags, for example. This is typically set to '1' for each new upstream
software release and incremented for intermediate PKGBUILD updates. The
variable is a positive integer, with an optional subrelease level
specified by adding another positive integer separated by a period
(i.e. in the form x.y).
*epoch*::
Used to force the package to be seen as newer than any previous versions
with a lower epoch, even if the version number would normally not trigger
such an upgrade. This value is required to be a positive integer; the
default value if left unspecified is '0'. This is useful when the version
numbering scheme of a package changes (or is alphanumeric), breaking normal
version comparison logic. See linkman:pacman[8] for more information on
version comparisons.
*pkgdesc*::
This should be a brief description of the package and its functionality.
Try to keep the description to one line of text and to not use the package's
name.
*url*::
This field contains a URL that is associated with the software being
packaged. This is typically the project's web site.
*license (array)*::
This field specifies the license(s) that apply to the package.
If multiple licenses are applicable, list all of them:
`license=('GPL' 'FDL')`.
*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 source array (e.g., `install=$pkgname.install`).
*changelog*::
Specifies a changelog file that is to be included in the package.
The changelog file should end in a single newline.
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 source array (e.g., `changelog=$pkgname.changelog`).
*source (array)*::
An array of source files required to build the package. Source files
must either reside in the same directory as the PKGBUILD, or be a
fully-qualified URL that makepkg can use to download the file.
To simplify the maintenance of PKGBUILDs, use the `$pkgname` and `$pkgver`
variables when specifying the download location, if possible.
Compressed files will be extracted automatically unless found in the
noextract array described below.
+
Additional architecture-specific sources can be added by appending an
underscore and the architecture name e.g., 'source_x86_64=()'. There must be a
corresponding integrity array with checksums, e.g. 'cksums_x86_64=()'.
+
It is also possible to change the name of the downloaded file, which is helpful
with weird URLs and for handling multiple source files with the same
name. The syntax is: `source=('filename::url')`.
+
makepkg also supports building developmental versions of packages using sources
downloaded from version control systems (VCS). For more information, see
<<VCS,Using VCS Sources>> below.
+
Files in the source array with extensions `.sig`, `.sign` or, `.asc` are
recognized by makepkg as PGP signatures and will be automatically used to verify
the integrity of the corresponding source file.
*validpgpkeys (array)*::
An array of PGP fingerprints. If this array is non-empty, makepkg will
only accept signatures from the keys listed here and will ignore the
trust values from the keyring. If the source file was signed with a
subkey, makepkg will still use the primary key for comparison.
+
Only full fingerprints are accepted. They must be uppercase and must not
contain whitespace characters.
*noextract (array)*::
An array of file names corresponding to those from the source array. Files
listed here will not be extracted with the rest of the source files. This
is useful for packages that use compressed data directly.
*cksums (array)*::
This array contains CRC checksums for every source file specified in the
source array (in the same order). makepkg will use this to verify source
file integrity during subsequent builds. If 'SKIP' is put in the array
in place of a normal hash, the integrity check for that source file will
be skipped. To easily generate cksums, run ``makepkg -g >> PKGBUILD''.
If desired, move the cksums line to an appropriate location. Note that
checksums generated by "makepkg -g" should be verified using checksum
values provided by the software developer.
*md5sums, sha1sums, sha224sums, sha256sums, sha384sums, sha512sums, b2sums (arrays)*::
Alternative integrity checks that makepkg supports; these all behave
similar to the cksums option described above. To enable use and generation
of these checksums, be sure to set up the `INTEGRITY_CHECK` option in
linkman:makepkg.conf[5].
*groups (array)*::
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.
*arch (array)*::
Defines on which architectures the given package is available (e.g.,
`arch=('i686' 'x86_64')`). Packages that contain no architecture specific
files should use `arch=('any')`. Valid characters for members of this array
are alphanumerics and ```_`''.
*backup (array)*::
An array of file names, without preceding slashes, that
should be backed up if the package is removed or upgraded. This is
commonly used for packages placing configuration files in '/etc'. See
`"Handling Config Files"` in linkman:pacman[8] for more information.
*depends (array)*::
An array of packages this package depends on to run. Entries in
this list should be surrounded with single quotes and contain at least
the package name. Entries can also include a version requirement of the
form 'name<>version', where `<>` is one of five comparisons: `>=` (greater
than or equal to), `<=` (less than or equal to), `=` (equal to), `>`
(greater than), or `<` (less than).
+
Additional architecture-specific depends can be added by appending an
underscore and the architecture name e.g., 'depends_x86_64=()'.
*makedepends (array)*::
An array of packages this package depends on to build but are not
needed at runtime. Packages in this list follow the same format as
depends.
+
Additional architecture-specific makedepends can be added by appending an
underscore and the architecture name e.g., 'makedepends_x86_64=()'.
*checkdepends (array)*::
An array of packages this package depends on to run its test suite
but are not needed at runtime. Packages in this list follow the same
format as depends. These dependencies are only considered when the
check() function is present and is to be run by makepkg.
+
Additional architecture-specific checkdepends can be added by appending an
underscore and the architecture name e.g., 'checkdepends_x86_64=()'.
*optdepends (array)*::
An array of packages (and accompanying reasons) that are not essential for
base functionality, but may be necessary to make full use of the contents
of this package. optdepends are currently for informational purposes only
and are not utilized by pacman during dependency resolution. Packages in
this list follow the same format as depends, with an optional description
appended. The format for specifying optdepends descriptions is:
optdepends=('python: for library bindings')
+
Additional architecture-specific optdepends can be added by appending an
underscore and the architecture name e.g., 'optdepends_x86_64=()'.
*conflicts (array)*::
An array of packages that will conflict with this package (i.e. they
cannot both be installed at the same time). This directive follows the
same format as depends. Versioned conflicts are supported using the
operators as described in `depends`.
+
Additional architecture-specific conflicts can be added by appending an
underscore and the architecture name e.g., 'conflicts_x86_64=()'.
*provides (array)*::
An array of ``virtual provisions'' this package provides. This allows
a package to provide dependencies other than its own package name. For
example, the dcron package can provide 'cron', which allows packages to
depend on 'cron' rather than 'dcron OR fcron'.
+
Versioned provisions are also possible, in the 'name=version' format. For
example, dcron can provide 'cron=2.0' to satisfy the 'cron>=2.0' dependency of
other packages. Provisions involving the `>` and `<` operators are invalid as
only specific versions of a package may be provided.
+
Additional architecture-specific provides can be added by appending an
underscore and the architecture name e.g., 'provides_x86_64=()'.
*replaces (array)*::
An array of packages this package should replace. This can be used
to handle renamed/combined packages. For example, if the 'j2re' package
is renamed to 'jre', this directive allows future upgrades to continue
as expected even though the package has moved. Versioned replaces are
supported using the operators as described in `depends`.
+
Sysupgrade is currently the only pacman operation that utilizes this field.
A normal sync or upgrade will not use its value.
+
Additional architecture-specific replaces can be added by appending an
underscore and the architecture name e.g., 'replaces_x86_64=()'.
*options (array)*::
This array allows you to override some of makepkg's default behavior
when building packages. To set an option, just include the option name
in the options array. To reverse the default behavior, place an ``!'' at
the front of the option. Only specify the options you specifically want
to override, the rest will be taken from linkman:makepkg.conf[5].
*NOTE:* 'force' is a now-removed option in favor of the top level 'epoch'
variable.
*strip*;;
Strip symbols from binaries and libraries. If you frequently
use a debugger on programs or libraries, it may be helpful to
disable this option.
*docs*;;
Save doc directories. If you wish to delete doc directories,
specify `!docs` in the array.
*libtool*;;
Leave libtool (.la) files in packages. Specify `!libtool` to
remove them.
*staticlibs*;;
Leave static library (.a) files in packages. Specify `!staticlibs` to
remove them (if they have a shared counterpart).
*emptydirs*;;
Leave empty directories in packages.
*zipman*;;
Compress man and info pages with gzip.
*ccache*;;
Allow the use of ccache during `build()`. More useful in its negative
form `!ccache` with select packages that have problems building
with ccache.
*distcc*;;
Allow the use of distcc during `build()`. More useful in its negative
form `!distcc` with select packages that have problems building
with distcc.
*buildflags*;;
Allow the use of user-specific buildflags (CPPFLAGS, CFLAGS, CXXFLAGS,
LDFLAGS) during `build()` as specified in linkman:makepkg.conf[5]. More
useful in its negative form `!buildflags` with select packages that
have problems building with custom buildflags.
*makeflags*;;
Allow the use of user-specific makeflags during `build()` as specified
in linkman:makepkg.conf[5]. More useful in its negative form
`!makeflags` with select packages that have problems building with
custom makeflags such as `-j2` (or higher).
*debug*;;
Add the user-specified debug flags (DEBUG_CFLAGS, DEBUG_CXXFLAGS) to
their counterpart buildflags as specified in linkman:makepkg.conf[5].
When used in combination with the `strip' option, a separate package
containing the debug symbols is created.
*lto*;;
Enable building packages using link time optimization. Adds '-flto'
to both CFLAGS and CXXFLAGS.
*xdata (array)*::
This array allows you to add additional metadata to the package.
This data is neither used by pacman nor by makepkg;
It has purely informational purpose, or may be interpreted by third-party tools.
+
All entries in that array must have the form 'key=value', where
'key' is an arbitrary non-empty string and 'value' must not contain an equal sign.
Furthermore, the key ``pkgtype'' is reserved for the makepkg program.
Packaging Functions
-------------------
In addition to the above directives, PKGBUILDs require a set of functions that
provide instructions to build and install the package. As a minimum, the
PKGBUILD must contain a `package()` function which installs all the package's
files into the packaging directory, with optional `prepare()`, `build()`, and
`check()` functions being used to create those files from source.
This is directly sourced and executed by makepkg, so anything that Bash or the
system has available is available for use here. Be sure any exotic commands
used are covered by the `makedepends` array.
If you create any variables of your own in any of these functions, it is
recommended to use the Bash `local` keyword to scope the variable to inside the
function.
*package() Function*::
The `package()` function is used to install files into the directory that
will become the root directory of the built package and is run after all
the optional functions listed below. The packaging stage is run using
fakeroot to ensure correct file permissions in the resulting package.
All other functions will be run as the user calling makepkg.
This function is run inside `$srcdir`.
*verify() Function*::
An optional `verify()` function can be specified to implement arbitrary
source authentication. The function should return a non-zero exit code when
verification fails. This function is run before sources are extracted.
This function is run inside `$startdir`.
*prepare() Function*::
An optional `prepare()` function can be specified in which operations to
prepare the sources for building, such as patching, are performed. This
function is run after the source extraction and before the `build()`
function. The `prepare()` function is skipped when source extraction
is skipped.
This function is run inside `$srcdir`.
*build() Function*::
The optional `build()` function is used to compile and/or adjust the source
files in preparation to be installed by the `package()` function.
This function is run inside `$srcdir`.
*check() Function*::
An optional `check()` function can be specified in which a package's
test-suite may be run. This function is run between the `build()` and
`package()` functions. Be sure any exotic commands used are covered by the
`checkdepends` array.
This function is run inside `$srcdir`.
All of the above variables such as `$pkgname` and `$pkgver` are available for
use in the packaging functions. In addition, makepkg defines the following
variables:
*srcdir*::
This contains the directory where makepkg extracts, or copies, all source
files.
+
*pkgdir*::
This contains the directory where makepkg bundles the installed package.
This directory will become the root directory of your built package. This
variable should only be used in the `package()` function.
*startdir*::
This contains the absolute path to the directory where the PKGBUILD is
located, which is usually the output of `$(pwd)` when makepkg is started.
Use of this variable is deprecated and strongly discouraged.
Package Splitting
-----------------
makepkg supports building multiple packages from a single PKGBUILD. This is
achieved by assigning an array of package names to the `pkgname` directive.
Each split package uses a corresponding packaging function with name
`package_foo()`, where `foo` is the name of the split package.
All options and directives for the split packages default to the global values
given in the PKGBUILD. Nevertheless, the following ones can be overridden within
each split package's packaging function:
`pkgdesc`, `arch`, `url`, `license`, `groups`, `depends`, `optdepends`,
`provides`, `conflicts`, `replaces`, `backup`, `options`, `install`, and
`changelog`.
Note that makepkg does not consider split package `depends` when checking
if dependencies are installed before package building and with `--syncdeps`.
All packages required to make the package are required to be specified in
the global `depends` and `makedepends` arrays.
An optional global directive is available when building a split package:
*pkgbase*::
The name used to refer to the group of packages in the output of makepkg
and in the naming of source-only tarballs. If not specified, the first
element in the `pkgname` array is used. Valid characters for this
variable are alphanumerics, and any of the following characters:
```@ . _ + -`''. Additionally, the variable is not allowed to start with
hyphens or dots.
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 perform an opposite action upon removal.
The exact time the script is run varies with each operation, and should be
self-explanatory. Note that during an upgrade operation, none of the install
or remove functions will be called.
Scripts are passed either one or two ``full version strings'', where a full
version string is either 'pkgver-pkgrel' or 'epoch:pkgver-pkgrel', if epoch is
non-zero.
*pre_install*::
Run right before files are extracted. One argument is passed:
new package full version string.
*post_install*::
Run right after files are extracted. One argument is passed:
new package full version string.
*pre_upgrade*::
Run right before files are extracted. Two arguments are passed in this
order: new package full version string, old package full version string.
*post_upgrade*::
Run after files are extracted. Two arguments are passed in this order:
new package full version string, old package full version string.
*pre_remove*::
Run right before files are removed. One argument is passed:
old package full version string.
*post_remove*::
Run right after files are removed. One argument is passed:
old package full version string.
To use this feature, create a file such as 'pkgname.install' and put it in the
same directory as the PKGBUILD script. Then use the install directive:
install=pkgname.install
The install script does not need to be specified in the source array. A
template install file is available in '{pkgdatadir}' as 'proto.install' for
reference with all of the available functions defined.
Using VCS Sources[[VCS]]
------------------------
Building a developmental version of a package using sources from a version
control system (VCS) is enabled by specifying the source in the form:
source=('directory::url#fragment?query')
Currently makepkg supports the Bazaar, Git, Subversion, Fossil and Mercurial
version control systems. For other version control systems, manual cloning of
upstream repositories must be done in the `prepare()` function.
Some <<VCS,VCS Sources>> like Git support pinning the checkout by a checksum of
its content using deterministic export functionality like ``git archive''.
The source URL is divided into four components:
*directory*::
(optional) Specifies an alternate directory name for makepkg to download
the VCS source into.
*url*::
The URL to the VCS repository. This must include the VCS in the URL protocol
for makepkg to recognize this as a VCS source. If the protocol does not
include the VCS name, it can be added by prefixing the URL with `vcs+`. For
example, using a Git repository over HTTPS would have a source URL in the
form:
`git+https://...`.
*fragment*::
(optional) Allows specifying a revision number or branch for makepkg to checkout
from the VCS. A fragment has the form `type=value`, for example to checkout a
given revision the source line would be `source=(url#revision=123)`. The
available types depends on the VCS being used:
*bzr*;;
revision (see `'bzr help revisionspec'` for details)
*fossil*;;
branch, commit, tag
*git*;;
branch, commit, tag
*hg*;;
branch, revision, tag
*svn*;;
revision
*query*::
(optional) Allows specifying whether a VCS checkout should be checked for
PGP-signed revisions. The source line should have the format
`source=(url#fragment?signed)` or `source=(url?signed#fragment)`. Currently
only supported by Git.
Example
-------
The following is an example PKGBUILD for the 'patch' package. For more
examples, look through the build files of your distribution's packages.
[source,sh]
-------------------------------
include::PKGBUILD-example.txt[]
-------------------------------
See Also
--------
linkman:makepkg[8], linkman:pacman[8], linkman:makepkg.conf[5]
include::footer.asciidoc[]

View file

@ -1,133 +0,0 @@
alpm-hooks(5)
=============
NAME
----
alpm-hooks - alpm hook file format
SYNOPSIS
--------
--------
[Trigger] (Required, Repeatable)
Operation = Install|Upgrade|Remove (Required, Repeatable)
Type = Path|Package (Required)
Target = <Path|PkgName> (Required, Repeatable)
[Action] (Required)
Description = ... (Optional)
When = PreTransaction|PostTransaction (Required)
Exec = <Command> (Required)
Depends = <PkgName> (Optional)
AbortOnFail (Optional, PreTransaction only)
NeedsTargets (Optional)
--------
DESCRIPTION
-----------
libalpm provides the ability to specify hooks to run before or after
transactions based on the packages and/or files being modified. Hooks consist
of a single '[Action]' section describing the action to be run and one or more
'[Trigger]' section describing which transactions it should be run for.
Hooks are read from files located in the system hook directory
+{datarootdir}/libalpm/hooks+, and additional custom directories specified in
linkman:pacman.conf[5] (the default is +{sysconfdir}/pacman.d/hooks+). The
file names are required to have the suffix ".hook". Hooks are run in
alphabetical order of their file name, where the ordering ignores the suffix.
TRIGGERS
--------
Hooks must contain at least one '[Trigger]' section that determines which
transactions will cause the hook to run. If multiple trigger sections are
defined the hook will run if the transaction matches *any* of the triggers.
*Operation =* Install|Upgrade|Remove::
Select the type of operation to match targets against. May be specified
multiple times. Installations are considered an upgrade if the package or
file is already present on the system regardless of whether the new package
version is actually greater than the currently installed version. For Path
triggers, this is true even if the file changes ownership from one package
to another. Required.
*Type =* Path|Package::
Select whether targets are matched against transaction packages or files.
See CAVEATS for special notes regarding Path triggers. 'File' is a deprecated
alias for 'Path' and will be removed in a future release. Required.
*Target =* <path|package>::
The path or package name to match against the active transaction.
Paths refer to the files in the package archive; the installation root
should *not* be included in the path. Shell-style glob patterns are
allowed. It is possible to invert matches by prepending a target with an
exclamation mark. May be specified multiple times. Required.
ACTIONS
-------
*Description =* ...::
An optional description that describes the action being taken by the
hook for use in front-end output.
*Exec =* <command>::
Command to run. Command arguments are split on whitespace. Values
containing whitespace should be enclosed in quotes. Required.
*When =* PreTransaction|PostTransaction::
When to run the hook. Required.
*Depends =* <package>::
Packages that must be installed for the hook to run. May be specified
multiple times.
*AbortOnFail*::
Causes the transaction to be aborted if the hook exits non-zero. Only
applies to PreTransaction hooks.
*NeedsTargets*::
Causes the list of matched trigger targets to be passed to the running hook
on 'stdin'.
OVERRIDING HOOKS
----------------
Hooks may be overridden by placing a file with the same name in a higher
priority hook directory. Hooks may be disabled by overriding them with
a symlink to '/dev/null'.
EXAMPLES
--------
--------
# Force disks to sync to reduce the risk of data corruption
[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Package
Target = *
[Action]
Depends = coreutils
When = PostTransaction
Exec = /usr/bin/sync
--------
CAVEATS
-------
There are situations when path triggers may act in unexpected ways. Hooks are
triggered using the file list of the installed, upgraded, or removed package.
When installing or upgrading a file that is extracted with a '.pacnew'
extension, the original file name is used in triggering the hook. When
removing a package, all files owned by that package can trigger a hook whether
or not they were actually present on the file system before package removal.
PostTransaction hooks will *not* run if the transaction fails to complete for
any reason.
include::footer.asciidoc[]

View file

@ -1,7 +0,0 @@
table th, table td {
padding: 0.2em 1em;
}
table td p.table {
margin: 0;
}

View file

@ -1,72 +0,0 @@
## linkman: macro
# Inspired by/borrowed from the Git source tree at Documentation/asciidoc.conf
#
# Usage: linkman:command[manpage-section]
#
# Note, {0} is the manpage section, while {target} is the command.
#
# Show man link as: <command>(<section>); if section is defined, else just show
# the command.
[macros]
(?su)[\\]?(?P<name>linkman):(?P<target>\S*?)\[(?P<attrlist>.*?)\]=
[attributes]
asterisk=&#42;
plus=&#43;
caret=&#94;
startsb=&#91;
endsb=&#93;
backslash=&#92;
tilde=&#126;
apostrophe=&#39;
backtick=&#96;
litdd=&#45;&#45;
ifdef::backend-docbook[]
[linkman-inlinemacro]
{0%{target}}
{0#<citerefentry>}
{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
{0#</citerefentry>}
endif::backend-docbook[]
ifdef::backend-docbook[]
ifndef::docbook-xsl-172[]
# "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
# v1.72 breaks with this because it replaces dots not in roff requests.
[listingblock]
<example><title>{title}</title>
<literallayout>
|
</literallayout>
{title#}</example>
endif::docbook-xsl-172[]
endif::backend-docbook[]
ifdef::doctype-manpage[]
ifdef::backend-docbook[]
[header]
template::[header-declarations]
<refentry>
<refentryinfo>
<date>{localdate}</date>
</refentryinfo>
<refmeta>
<refentrytitle>{mantitle}</refentrytitle>
<manvolnum>{manvolnum}</manvolnum>
<refmiscinfo class="source">Pacman</refmiscinfo>
<refmiscinfo class="version">{pacman_version}</refmiscinfo>
<refmiscinfo class="manual">Pacman Manual</refmiscinfo>
</refmeta>
<refnamediv>
<refname>{manname}</refname>
<refpurpose>{manpurpose}</refpurpose>
</refnamediv>
endif::backend-docbook[]
endif::doctype-manpage[]
ifdef::backend-xhtml11[]
[linkman-inlinemacro]
<a href="{target}.{0}.html">{target}{0?({0})}</a>
endif::backend-xhtml11[]

View file

@ -1,36 +0,0 @@
See the pacman website at https://archlinux.org/pacman/[] for current
information on pacman and its related tools.
Bugs
----
Bugs? You must be kidding; there are no bugs in this software. But if we
happen to be wrong, please report them to the issue tracker at
link:https://gitlab.archlinux.org/pacman/pacman/-/issues[] with specific
information such as your command-line, the nature of the bug, and even
the package database if it helps.
Authors
-------
Current maintainers:
* Allan McRae <allan@archlinux.org>
* Andrew Gregory <andrew.gregory.8@gmail.com>
* Morgan Adamiec <morganamilo@archlinux.org>
Past major contributors:
* Judd Vinet <jvinet@zeroflux.org>
* Aurelien Foret <aurelien@archlinux.org>
* Aaron Griffin <aaron@archlinux.org>
* Dan McGee <dan@archlinux.org>
* Xavier Chantry <shiningxc@gmail.com>
* Nagy Gabor <ngaba@bibl.u-szeged.hu>
* Dave Reisner <dreisner@archlinux.org>
* Eli Schwartz <eschwartz@archlinux.org>
For additional contributors, use `git shortlog -s` on the pacman.git
repository.

View file

@ -1,258 +0,0 @@
Pacman Home Page
================
A simple library-based package manager.
Introduction
------------
pacman is a utility which manages software packages in Linux. It uses simple
compressed files as a package format, and maintains a text-based package
database (more of a hierarchy), just in case some hand tweaking is necessary.
pacman does not strive to "do everything." It will add, remove and upgrade
packages in the system, and it will allow you to query the package database for
installed packages, files and owners. It also attempts to handle dependencies
automatically and can download packages from a remote server.
History
~~~~~~~
Version 2.0 of pacman introduced the ability to sync packages (the '\--sync'
option) with a master server through the use of package databases. Prior to
this, packages would have to be installed manually using the '\--add' and
'\--upgrade' operations.
Version 3.0 was the switch to a two-part pacman -- a back-end named libalpm
(library for Arch Linux Package Management) and the familiar pacman front-end.
Speed in many cases was improved, along with dependency and conflict resolution
being able to handle a much wider variety of cases. The switch to a
library-based program should also make it easier in the future to develop
alternative front ends.
Version 4.0 added package signing and verification capabilities to the entire
makepkg/repo-add/pacman toolchain via GnuPG and GPGME.
Version 5.0 added support for pre/post-transaction hooks and sync database file
list operations.
Version 6.0 added support for parallel downloads.
Documentation
-------------
Man Pages
~~~~~~~~~
There are several man pages available for the programs, utilities, and
configuration files dealing with pacman.
* linkman:alpm-hooks[5]
* linkman:BUILDINFO[5]
* linkman:PKGBUILD[5]
* linkman:libalpm[3]
* linkman:makepkg[8]
* linkman:makepkg-template[1]
* linkman:makepkg.conf[5]
* linkman:pacman[8]
* linkman:pacman-key[8]
* linkman:pacman-conf[8]
* linkman:pacman.conf[5]
* linkman:repo-add[8]
* linkman:vercmp[8]
Changelog
~~~~~~~~~
For a good idea of what is going on in pacman development, take a look at the
link:https://gitlab.archlinux.org/pacman/pacman[Git summary page] for the
project.
See the most recent
link:https://gitlab.archlinux.org/pacman/pacman/-/blob/master/NEWS[NEWS]
file for a not-as-frequently-updated list of changes. However, this should
contain the biggest changes in a format more concise than the commit log.
Releases
--------
[frame="none",grid="none",options="autowidth",cols="3*a"]
|======
|
[frame="topbot",grid="none",options="header,autowidth"]
!======
!Version !Date
!7.0.0 !2024-07-14
!6.1.0 !2024-03-04
!6.0.1 !2021-09-04
!6.0.0 !2021-05-20
!6.0.0alpha1 !2020-12-04
!5.2.1 !2019-11-01
!5.2.0 !2019-10-21
!5.1.3 !2019-03-01
!5.1.2 !2018-12-25
!5.1.1 !2018-07-27
!5.1.0 !2018-05-28
!5.0.2 !2017-06-03
!5.0.1 !2016-02-23
!5.0.0 !2016-01-30
!4.2.1 !2015-02-20
!4.2.0 !2014-12-19
!4.1.2 !2013-06-18
!4.1.1 !2013-05-07
!4.1.0 !2013-04-01
!4.1.0rc1 !2013-03-09
!4.0.3 !2012-04-07
!4.0.2 !2012-02-11
!4.0.1 !2011-11-20
!4.0.0 !2011-10-13
!4.0.0rc2 !2011-09-22
!4.0.0rc1 !2011-08-11
!3.5.4 !2011-08-10
!3.5.3 !2011-06-07
!3.5.2 !2011-04-18
!3.5.1 !2011-03-23
!3.5.0 !2011-03-16
!3.4.3 !2011-01-22
!3.4.2 !2010-12-29
!3.4.1 !2010-09-03
!======
|
[frame="topbot",grid="none",options="header,autowidth"]
!======
!Version !Date
!3.4.0 !2010-06-16
!3.3.3 !2009-11-10
!3.3.2 !2009-10-05
!3.3.1 !2009-09-22
!3.3.0 !2009-08-02
!3.2.2 !2009-01-05
!3.2.1 !2008-08-26
!3.2.0 !2008-07-30
!3.1.4 !2008-04-01
!3.1.3 !2008-03-06
!3.1.2 !2008-02-20
!3.1.1 !2008-01-20
!3.1.0 !2008-01-09
!3.0.6 !2007-09-16
!3.0.5 !2007-06-17
!3.0.4 !2007-05-08
!3.0.3 !2007-04-28
!3.0.2 !2007-04-23
!3.0.1 !2007-04-04
!3.0.0 !2007-03-25
!2.9.8 !2006-02-02
!2.9.7 !2005-09-16
!2.9.7-TEST3 !2005-09-11
!2.9.7-TEST2 !2005-09-07
!2.9.7-TEST !2005-08-19
!2.9.6 !2005-06-10
!2.9.5 !2005-01-11
!2.9.4 !2004-12-20
!2.9.3 !2004-12-19
!2.9.2 !2004-09-25
!2.9.1 !2004-09-25
!2.9 !2004-09-18
!2.8.4 !2004-08-23
!2.8.3 !2004-08-04
!======
|
[frame="topbot",grid="none",options="header,autowidth"]
!======
!Version !Date
!2.8.2 !2004-07-22
!2.8.1 !2004-07-17
!2.8 !2004-07-03
!2.7.9 !2004-04-30
!2.7.8 !2004-04-29
!2.7.7 !2004-04-15
!2.7.6 !2004-04-04
!2.7.5 !2004-03-02
!2.7.4 !2004-02-18
!2.7.3 !2004-02-07
!2.7.2 !2004-01-04
!2.7.1 !2003-12-21
!2.7 !2003-11-25
!2.6.4 !2003-10-17
!2.6.3 !2003-10-01
!2.6.2 !2003-09-29
!2.6.1 !2003-09-15
!2.6 !2003-09-03
!2.5.1 !2003-07-12
!2.5 !2003-05-30
!2.4.1 !2003-04-19
!2.4 !2003-04-11
!2.3.2 !2003-03-17
!2.3.1 !2003-03-14
!2.3 !2003-02-27
!2.2 !2002-12-11
!2.1 !2002-09-16
!2.0 !2002-08-09
!1.23 !2002-04-30
!1.22 !2002-04-12
!1.21 !2002-04-03
!1.2 !2002-03-18
!1.1 !2002-03-10
!1.0 !2002-02-25
!======
|======
Source code for releases since moving to gitlab is available at
link:https://gitlab.archlinux.org/pacman/pacman/-/releases[].
Source code for historical releases is available at
link:https://sources.archlinux.org/other/pacman/[]. To install, download the newest
available source tarball, unpack it in a directory, and run the three magic
commands:
$ meson build
$ ninja -C build
# ninja -C build install
You may wish to read the options presented by `meson` in order to
set appropriate paths and build options that are correct for your system.
Development
-----------
Mailing List
~~~~~~~~~~~~
There is a mailing list devoted to pacman development, hosted by Arch Linux.
link:https://lists.archlinux.org/listinfo/pacman-dev/[Subscribe] or
link:https://lists.archlinux.org/pipermail/pacman-dev/[view the archives].
Source Code
~~~~~~~~~~~
Development of pacman is currently done in Git. The central repository is
hosted by Arch Linux, although some of the developers have their own trees (ask
on the above mailing lists if you are interested in finding the locations of
these trees).
The current development tree can be fetched with the following command:
git clone https://gitlab.archlinux.org/pacman/pacman.git
which will fetch the full development history into a directory named pacman.
You can browse the source as well using
link:https://gitlab.archlinux.org/pacman/pacman/[gitlab].
If you are interested in hacking on pacman, it is highly recommended you join
the mailing list mentioned above, as well as take a quick glance at our
link:HACKING.html[HACKING] document.
link:submitting-patches.html[submitting-patches] is also a recommended read.
Not as familiar with code as you'd like to be, but still want to help out? If
you speak a foreign language, you can help by either creating or updating a
translation file for your native language. Instructions can be found in
link:translation-help.html[translation-help].
Bugs
----
If you find bugs (which is quite likely), please report them to the issue
tracker at link:https://gitlab.archlinux.org/pacman/pacman/-/issues[] with
specific information such as your command-line, the nature of the bug, and even
the package database if it helps.
Copyright
---------
pacman is Copyright (C) 2006-2025 Pacman Development Team
<pacman-dev@lists.archlinux.org> and Copyright (C) 2002-2006 Judd Vinet
<jvinet@zeroflux.org> and is licensed through the GNU General Public License,
version 2 or later.

View file

@ -1,118 +0,0 @@
makepkg-template(1)
===================
Name
----
makepkg-template - package build templating utility
Synopsis
--------
'makepkg-template' [options]
Description
-----------
'makepkg-template' is a script to ease the work of maintaining multiple similar
PKGBUILDs. It allows you to move most of the code from the PKGBUILD into a
template file and uses markers to allow in-place updating of existing PKGBUILDs
if the template has been changed.
Template files can contain any code allowed in a PKGBUILD. You can think of
them like external files included with "." or "source", but they will be
inlined into the PKGBUILD by 'makepkg-template' so you do not depend on the
template file when building the package.
Markers are bash comments in the form of:
# template start; key=value; key2=value2; ...
and
# template end;
Currently used keys are: name (mandatory) and version. Template names are limited to
alphanumerics, "@", "+", ".", "-", and "_". Versions are limited to numbers and ".".
For initial creation there is a one line short cut which does not need an end marker:
# template input; key=value;
Using this short-cut will result in 'makepkg-template' replacing it with start
and end markers and the template code on the first run.
Template files should be stored in one directory and filenames should be
"$template_name-$version.template" with a symlink "$template_name.template"
pointing to the most recent template. If the version is not set in the marker,
'makepkg-template' will automatically use the target of "$template_name.template",
otherwise the specified version will be used. This allows for easier
verification of untrusted PKGBUILDs if the template is trusted. You verify the
non-template code and then use a command similar to this:
diff -u <(makepkg-template -o -) PKGBUILD
Template files may also contain markers leading to nested templates in the
resulting PKGBUILD. If you use markers in a template, please set the version
you used/tested with in the start/input marker so other people can properly
recreate from templates.
Options
-------
*-p, \--input* <build script>::
Read the package script `build script` instead of the default.
*-o, \--output* <build script>::
Write the updated file to `build script` instead of overwriting the input file.
*-n, \--newest*::
Always use the newest available template file.
*\--template-dir* <dir>::
Change the dir where we are looking for template files. This option may be
given multiple times in which case files found in directory given last will
take precedence.
Example PKGBUILD
----------------
pkgname=perl-config-simple
pkgver=4.58
pkgrel=1
pkgdesc="simple configuration file class"
arch=('any')
license=('PerlArtistic' 'GPL')
depends=('perl')
source=("http://search.cpan.org/CPAN/authors/id/S/SH/SHERZODR/Config-Simple-${pkgver}.tar.gz")
sha256sums=('dd9995706f0f9384a15ccffe116c3b6e22f42ba2e58d8f24ed03c4a0e386edb4')
_distname="Config-Simple"
# template start; name=perl-module; version=1.0;
_distdir="${_distname}-${pkgver}"
url="https://metacpan.org/release/${_distname}"
options+=('!emptydirs')
build() {
cd "$srcdir/$_distdir"
perl Makefile.PL INSTALLDIRS=vendor
make
}
check() {
cd "$srcdir/$_distdir"
make test
}
package() {
cd "$srcdir/$_distdir"
make DESTDIR="$pkgdir" install
}
# template end;
See Also
--------
linkman:makepkg[8], linkman:PKGBUILD[5]
include::footer.asciidoc[]

View file

@ -1,382 +0,0 @@
makepkg(8)
==========
Name
----
makepkg - package build utility
Synopsis
--------
'makepkg' [options] [ENVVAR=value] [ENVVAR+=value] ...
Description
-----------
'makepkg' is a script to automate the building of packages. The requirements for
using the script are a build-capable *nix platform and a custom build script
for each package you wish to build (known as a PKGBUILD). See
linkman:PKGBUILD[5] for details on creating your own build scripts.
The advantage to a script-based build is that the work is only done once. Once
you have the build script for a package, 'makepkg' will do the rest: download and
validate source files, check dependencies, configure the build-time settings,
build the package, install the package into a temporary root, make
customizations, generate meta-info, and package the whole thing up for pacman
to use.
NOTE: 'makepkg' uses your current locale by default and does not unset it when
building packages. If you wish to share your build output with others when
seeking help or for other purposes, you may wish to run "`LC_ALL=C makepkg`" so
your logs and output are not localized.
Options
-------
*-A, \--ignorearch*::
Ignore a missing or incomplete arch field in the build script. This is
for rebuilding packages from source when the PKGBUILD may be slightly
outdated and not updated with an `arch=('yourarch')` field.
*-c, \--clean*::
Clean up leftover work files and directories after a successful build.
*\--config* <file>::
Use an alternate configuration file instead of the +{sysconfdir}/makepkg.conf+
default.
*-d, \--nodeps*::
Do not perform any dependency checks. This will let you override and
ignore any dependencies required. There is a good chance this option
will break the build process if all of the dependencies are not
installed.
*-e, \--noextract*::
Do not extract source files or run the prepare() function (if present);
use whatever source already exists in the $srcdir/ directory. This is
handy if you want to go into $srcdir/ and manually patch or tweak code,
then make a package out of the result. Keep in mind that creating a
patch may be a better solution to allow others to use your PKGBUILD.
*\--verifysource*::
For each source file in the source array of PKGBUILD, download the file
if required and perform the integrity checks. No extraction or build is
performed. Dependencies specified in the PKGBUILD will not be handled
unless `--syncdeps` is used. Useful for performing subsequent offline
builds.
*-f, \--force*::
makepkg will not build a package if a built package already exists in
the `PKGDEST` (set in linkman:makepkg.conf[5]) directory, which may
default to the current directory. This allows the built package to be
overwritten.
*-g, \--geninteg*::
For each source file in the source array of PKGBUILD, download the file
if required and generate integrity checks. The integrity checks generated
are determined by the checks present in the PKGBUILD, falling back to the
value of the INTEGRITY_CHECK array in makepkg.conf(5) if these are absent.
This output can be redirected into your PKGBUILD for source validation
using "`makepkg -g >> PKGBUILD`".
*--skipinteg*::
Do not perform any integrity checks (checksum and PGP) on source files.
*\--skipchecksums*::
Do not verify checksums of source files.
*\--skippgpcheck*::
Do not verify PGP signatures of source files.
*-h, \--help*::
Output syntax and command line options.
*--holdver*::
When using VCS sources (linkman:PKGBUILD[5]) any currently checked out source
will not be updated to the latest revision.
*-i, \--install*::
Install or upgrade the package after a successful build using
linkman:pacman[8].
*-L, \--log*::
Enable logging. This will use the *tee* program to send the output of each
of the PKGBUILD functions to both the console and to a text file in the
build directory named `pkgbase-pkgver-pkgrel-arch-<function>.log`.
As mentioned above, the logs will be localized so you may want to set your
locale accordingly if sharing the log output with others.
*-m, \--nocolor*::
Disable color in output messages.
*-o, \--nobuild*::
Download and extract files, run the prepare() function, but do not build
them. Useful with the '\--noextract' option if you wish to tweak the files
in $srcdir/ before building.
*-p* <buildscript>::
Read the package script `buildscript` instead of the `PKGBUILD` default;
see linkman:PKGBUILD[5]. The `buildscript` must be located in the directory
makepkg is called from.
*-r, \--rmdeps*::
Upon successful build, remove any dependencies installed by makepkg
during dependency auto-resolution and installation when using `-s`.
*-R, \--repackage*::
Repackage contents of the package without rebuilding the package. This
is useful if you forgot, for example, a dependency or install file in your
PKGBUILD and the build itself will not change.
*-s, \--syncdeps*::
Install missing dependencies using pacman. When build-time or run-time
dependencies are not found, pacman will try to resolve them. If
successful, the missing packages will be downloaded and installed.
*-S, \--source*::
Do not actually build the package, but build a source-only tarball that
does not include sources that can be fetched via a download URL. This is
useful for passing a single tarball to another program such as a chroot,
remote builder, or a tarball upload. Because integrity checks are verified,
all source files of the package need to be present or downloadable.
*-V, \--version*::
Display version information.
*-C, \--cleanbuild*::
Clean build artifacts from previous runs of makepkg in the current
directory by removing $srcdir before building the package.
*-D* <dir>, *\--dir* <dir> ::
Change to directory <dir> before reading the PKGBUILD or doing anything else.
*\--allsource*::
Do not actually build the package, but build a source-only tarball that
includes all sources, including those that are normally downloaded via
makepkg. This is useful for passing a single tarball to another program
such as a chroot or remote builder. It will also satisfy requirements of
the GPL when distributing binary packages.
*\--check*::
Run the check() function in the PKGBUILD, overriding the setting in
linkman:makepkg.conf[5].
*\--noarchive*::
Do not create the archive at the end of the build process. This can be
useful to test the package() function or if your target distribution does
not use pacman.
*\--nocheck*::
Do not run the check() function in the PKGBUILD or handle the checkdepends.
*\--noprepare*::
Do not run the prepare() function in the PKGBUILD.
*\--noverify*::
Do not run the verify() function in the PKGBUILD.
*\--sign*::
Sign the resulting package with gpg, overriding the setting in
linkman:makepkg.conf[5].
*\--nosign*::
Do not create a signature for the built package.
*\--key* <key>::
Specify a key to use when signing packages, overriding the GPGKEY setting
in linkman:makepkg.conf[5]. If not specified in either location, the
default key from the keyring will be used.
*\--noconfirm*::
(Passed to pacman) Prevent pacman from waiting for user input before
proceeding with operations.
*\--needed*::
(Passed to pacman) Tell pacman not to reinstall a target if it is already
up-to-date. (used with '-i' / '\--install').
*\--asdeps*::
(Passed to pacman) Install packages as non-explicitly installed (used
with '-i' / '\--install').
*\--noprogressbar*::
(Passed to pacman) Prevent pacman from displaying a progress bar;
useful if you are redirecting makepkg output to file.
*\--packagelist*::
List the package filenames that would be produced without building. Listed
package filenames include PKGDEST and PKGEXT.
*\--printsrcinfo*::
Generate and print the SRCINFO file to stdout.
Additional Features
-------------------
makepkg supports building development versions of packages without having to
manually update the pkgver in the PKGBUILD. This was formerly done using the
separate utility 'versionpkg'. See linkman:PKGBUILD[5] for details on how to
set up a development PKGBUILD.
Reproducibility
---------------
makepkg is designed to be compatible with
link:https://reproducible-builds.org/docs/[Reproducible Builds]. If the
**SOURCE_DATE_EPOCH** environment variable is set, it will be exported to
subprocesses, and source and package file modification times and package
metadata will be unified based on the timestamp specified.
If the **SOURCE_DATE_EPOCH** environment variable is not set, makepkg will use
its own start date for internal use, but will not unify source file timestamps
before building.
Environment Variables
---------------------
**MAKEPKG_LIBRARY**="/path/to/directory"::
Use an alternative libmakepkg path instead of the {libmakepkgdir} default.
**PACMAN**::
The command that will be used to check for missing dependencies and to
install and remove packages. Pacman's '-Qq', '-Rns', '-S', '-T', and '-U'
operations must be supported by this command. If the variable is not
set or empty, makepkg will fall back to `pacman'.
**MAKEPKG_CONF=**"/path/to/file"::
Use an alternate config file instead of the +{sysconfdir}/makepkg.conf+
default.
**MAKEPKG_GIT_CONFIG=**"/path/to/file"::
Use an alternate config file for Git instead of the
+{sysconfdir}/makepkg.d/gitconfig+ default. makepkg always prevents Git
from loading any other config files.
**PKGDEST=**"/path/to/directory"::
Directory where the resulting packages will be stored. Overrides the
corresponding value defined in linkman:makepkg.conf[5].
**SRCDEST=**"/path/to/directory"::
Directory where the downloaded sources will be stored. Overrides the
corresponding value defined in linkman:makepkg.conf[5].
**SRCPKGDEST=**"/path/to/directory"::
Directory where source package files will be stored. Overrides the
corresponding value defined in linkman:makepkg.conf[5].
**LOGDEST=**"/path/to/directory"::
Directory where generated log files will be stored. Overrides the
corresponding value defined in linkman:makepkg.conf[5].
**PACKAGER=**"John Doe <john@doe.com>"::
String to identify the creator of the resulting package. Overrides
the corresponding value defined in linkman:makepkg.conf[5].
**BUILDDIR=**"/path/to/directory"::
Directory where the package will be built. Overrides the corresponding
value defined in linkman:makepkg.conf[5].
**CARCH=**"(i686|x86_64)"::
Force build for a specific architecture. Useful for cross-compiling.
Overrides the corresponding value defined in linkman:makepkg.conf[5].
**PKGEXT=**".pkg.tar.gz", **SRCEXT=**".src.tar.gz"::
Sets the compression used when making compiled or source packages.
Overrides the corresponding value defined in linkman:makepkg.conf[5].
**GNUPGHOME=**"/path/to/directory"::
Directory where the gpg keyring for signing the built package is stored.
**GPGKEY=**"keyid"::
Specify a key to use when signing packages, overriding the GPGKEY setting
in linkman:makepkg.conf[5].
**SOURCE_DATE_EPOCH=**"<date>"::
Used for link:https://reproducible-builds.org/docs/[Reproducible Builds].
**BUILDTOOL=**"<name>"::
The name of a tool ecosystem used to set up the build environment. Used for
defining a spec for reproducible builds, e.g. the linkman:makepkg.conf[5]
used.
**BUILDTOOLVER=**"<version>"::
The version of the '$BUILDTOOL' used.
**MAKEPKG_LINT_PKGBUILD=**0::
Setting to 0 disables PKGBUILD linting within makepkg. Useful on systems
with slow bash subshell operations, or on PKGBUILDs with extreme amounts of
package splitting.
Configuration
-------------
See linkman:makepkg.conf[5] for more details on configuring makepkg using the
'makepkg.conf' file.
Errors
------
On exit, makepkg will return one of the following error codes.
0::
Normal exit condition.
1::
Unknown cause of failure.
2::
Error in configuration file.
3::
User specified an invalid option.
4::
Error in user-supplied function in PKGBUILD.
5::
Failed to create a viable package.
6::
A source or auxiliary file specified in the PKGBUILD is
missing.
7::
The PKGDIR is missing.
8::
Failed to install dependencies.
9::
Failed to remove dependencies.
10::
User attempted to run makepkg as root.
11::
User lacks permissions to build or install to a given
location.
12::
Error parsing PKGBUILD.
13::
A package has already been built.
14::
The package failed to install.
15::
Programs necessary to run makepkg are missing.
16::
Specified GPG key does not exist or failed to sign package.
17::
The local repository is not a clone of the source repository
specified in PKGBUILD.
See Also
--------
linkman:makepkg.conf[5], linkman:PKGBUILD[5], linkman:pacman[8]
include::footer.asciidoc[]

455
doc/makepkg.8.in Normal file
View file

@ -0,0 +1,455 @@
.TH makepkg 8 "January 30, 2006" "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 options
This array allows you to override some of makepkg's default behaviour
when building packages. To set an option, just include the option name
in the \fBoptions\fP array.
.TP
.RS
\fIAvailable Options:\fP
.RS
.TP
.B FORCE
force the package to be upgraded by \fB--sysupgrade\fP, even
if its an older version.
.TP
.B KEEPDOCS
do not remove /usr/share/doc and /usr/share/info directories.
.TP
.B NOSTRIP
do not strip debugging symbols from binaries and libraries.
.RE
.RE
.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
This field specifies the license(s) that apply to the package. Commonly-used
licenses are typically found in \fI/usr/share/licenses/common\fP. If you
see the package's license there, simply reference it in the license field
(eg, \fBlicense="GPL"\fP). If the package provides a license not found in
\fI/usr/share/licenses/common\fP, then you should include the license in
the package itself and set \fBlicense="custom"\fP or \fBlicense="custom:LicenseName"\fP.
The license itself should be placed in a directory called
\fI$startdir/pkg/usr/share/licenses/$pkgname\fP.
.TP
.RE
If multiple licenses are applied, use the array form: \fBlicenses=('GPL' 'FDL')\fP
.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 >>PKGBUILD\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 "\-B, \-\-noccache"
Do not use ccache during build.
.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 "\-e, \-\-noextract"
Do not extract source files. Instead, use whatever already exists in the
src/ directory. This is handy if you want to go into src and manually
patch/tweak code, then make a package out of the result.
.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 "\-S, \-\-sudosync"
Install missing dependencies using pacman and sudo. This is the same as \fB-s\fP
except that makepkg will call pacman with sudo. This means you don't have to
build as root to use dependency auto-resolution.
.TP
.B "\-w <destdir>"
Write the resulting package file to the directory \fI<destdir>\fP instead of the
current working directory.
.TP
.B "\-\-noconfirm"
When calling pacman to resolve dependencies or conflicts, makepkg can pass
the \fI--noconfirm\fP option to it so it does not wait for any user
input before proceeding with operations.
.TP
.B "\-\-noprogressbar"
When calling pacman, makepkg can pass the \fI--noprogressbar\fP option to it.
This is useful if one is directing makepkg's output to a non-terminal (ie, a file).
.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

View file

@ -1,312 +0,0 @@
makepkg.conf(5)
===============
Name
----
makepkg.conf - makepkg configuration file
Synopsis
--------
{sysconfdir}/makepkg.conf, $XDG_CONFIG_HOME/pacman/makepkg.conf, ~/.makepkg.conf
Description
-----------
Configuration options for makepkg are stored in makepkg.conf. This file is
sourced so you can include any special compiler flags you wish to use. This is
helpful when building for different architectures or with different
optimizations. However, only the variables described below are exported to the
build environment.
NOTE: This does not guarantee that all package Makefiles will use your exported
variables. Some of them are non-standard.
The system-wide configuration file is found in {sysconfdir}/makepkg.conf.
Specific additions (e.g. build flags for additional languages) can be placed
in {sysconfdir}/makepkg.conf.d/*.conf.
Individual options can be overridden (or added to) on a per-user basis in
$XDG_CONFIG_HOME/pacman/makepkg.conf or ~/.makepkg.conf, with the former
taking priority.
The default file is fairly well commented, so it may be easiest to simply
follow directions given there for customization.
Options
-------
**DLAGENTS=(**\'protocol::/path/to/command [options]' ...**)**::
Sets the download agents used to fetch source files specified with a URL in
the linkman:PKGBUILD[5] file. Options can be specified for each command as
well, and any protocol can have a download agent. Any spaces in option
arguments are required to be escaped to avoid being split. Several
examples are provided in the default makepkg.conf.
+
If present, `%u` will be replaced with the download URL. Otherwise, the
download URL will be placed on the end of the command. If present, `%o` will
be replaced with the local file name, plus a ``.part'' extension, which allows
makepkg to handle resuming file downloads.
**VCSCLIENTS=(**\'protocol::package' ...**)**::
Sets the packages required to fetch version controlled source files. When
required, makepkg will check that these packages are installed or are included
in the `depends` or `makedepends` arrays in the PKGBUILD.
**CARCH=**"carch"::
Specifies your computer architecture; possible values include such things
as ``i686'', ``x86_64'', ``ppc'', etc. This should be automatically set on
installation.
**CHOST=**"chost"::
A string such as ``i686-pc-linux-gnu''; do not touch this unless you know what
you are doing. This can be commented out by most users if desired.
**NPROC=**""::
Sets the number of processors to use for parallel jobs in makepkg.
Note: this does not affect parallelization of tasks during ``build()`` and
related functions.
**CPPFLAGS=**"cppflags"::
Flags used for the C preprocessor; see CFLAGS for more information.
**CFLAGS=**"cflags"::
Flags used for the C compiler. This is a key part to the use of makepkg.
Usually several options are specified, and the most common string resembles
something like this: ``-march=i686 -O2 -pipe''. Another useful option may
be `-mcpu` in place of `-march`. Read gcc(1) for more details on the wide
variety of compiler flags available.
**CXXFLAGS=**"cxxflags"::
Flags used for the C++ compiler; see CFLAGS for more info.
**LDFLAGS=**"ldflags"::
Flags used for the linker. Several options may be specified with common
usage resembling ``-Wl,--hash-style=gnu''. Read ld(1) for more details on
available linker flags.
**LTOFLAGS=**"ltoflags"::
Additional compiler and linker flags appended to `CFLAGS`, `CXXFLAGS`
and `LDFLAGS` when building with link time optimization. If empty,
``-flto'' is used.
**MAKEFLAGS=**"makeflags"::
This is often used to set the number of jobs used; for example, `-j2`.
Other flags that make accepts can also be passed.
**DEBUG_CFLAGS=**"debug_cflags"::
Additional compiler flags appended to `CFLAGS` for use in debugging. Usually
this would include: ``-g''. Read gcc(1) for more details on the wide
variety of compiler flags available.
**DEBUG_CXXFLAGS=**"debug_cxxflags"::
Debug flags used for the C++ compiler; see DEBUG_CFLAGS for more info.
**BUILDENV=(**!distcc !color !ccache check !sign**)**::
This array contains options that affect the build environment; the defaults
are shown here. All options should always be left in the array; to enable
or disable an option, simply remove or add an ``!'' at the front of the
option. If an option is specified multiple times, the final value takes
precedence. Each option works as follows:
*distcc*;;
Use the distributed C/C++/ObjC compiler to spread compilation among
multiple machines. If this is enabled, `DISTCC_HOSTS` must be specified
as well.
*color*;;
Colorize output messages, making output easier to read.
*ccache*;;
Use ccache to cache compilation by default. This allows for faster
compiles if you are continuously recompiling the same packages. It can
be disabled for individual packages by placing `!ccache` in the
PKGBUILD options array.
*check*;;
Run the check() function if present in the PKGBUILD. This can be
enabled or disabled for individual packages through the use of
makepkg's '\--check' and '\--nocheck' options, respectively.
*sign*;;
Generate a PGP signature file using GnuPG. This will execute 'gpg
\--detach-sign' on the built package to generate a detached
signature file, using the GPG agent, if it is available. The signature
file will be the entire file name of the package with a ``.sig''
extension.
**DISTCC_HOSTS=**"host1 ..."::
If using DistCC, this is used to specify a space-delimited list of hosts
running in the DistCC cluster. In addition, you will want to modify your
`MAKEFLAGS`.
**BUILDDIR=**"/path/to/directory"::
If this value is not set, packages will, by default, be built in
subdirectories of the directory that makepkg is called from. This
option allows setting the build location to another directory.
Incorrect use of `$startdir` in a PKGBUILD may cause building with
this option to fail.
**GPGKEY=**""::
Specify a key to use for GPG signing instead of the default key in the
keyring. Can be overridden with makepkg's '\--key' option.
**OPTIONS=(**!strip docs libtool staticlibs emptydirs ...**)**::
This array contains options that affect default packaging. They are
equivalent to options that can be placed in the PKGBUILD; the defaults are
shown here. All options should always be left in the array; to enable or
disable an option, simply remove or add an ``!'' at the front of the
option. If an option is specified multiple times, the final value takes
precedence. Each option works as follows:
*strip*;;
Strip symbols from binaries and libraries. If you frequently use a
debugger on programs or libraries, it may be helpful to disable this
option.
*docs*;;
Save doc directories. If you wish to delete doc directories, specify
`!docs` in the array. The directories affected are specified by the
`DOC_DIRS` variable.
*libtool*;;
Leave libtool (.la) files in packages. Specify `!libtool` to remove
them.
*staticlibs*;;
Leave static library (.a) files in packages. Specify `!staticlibs` to
remove them, if they have a shared counterpart.
*emptydirs*;;
Leave empty directories in packages.
*zipman*;;
Compress manual (man and info) pages with gzip. The directories
affected are specified by the `MAN_DIRS` variable.
*purge*;;
Remove files specified by the `PURGE_TARGETS` variable from the
package.
*debug*;;
Add the user-specified debug flags as specified in DEBUG_CFLAGS and
DEBUG_CXXFLAGS to their counterpart buildflags. Creates a separate
package containing the debug symbols when used with `strip'.
*lto*;;
Enable building packages using link time optimization. Adds the
flags specified in LTOFLAGS to CFLAGS, CXXFLAGS and LDFLAGS (or
``-flto'' if LTOFLAGS is empty).
*autodeps*;;
Enable the automatic addition of libraries to the depends and
provides arrays. Search library directories are controlled by
the LIB_DIRS variable defined below.
**INTEGRITY_CHECK=(**check1 ...**)**::
File integrity checks to use. Multiple checks may be specified; this
affects both generation and checking. The current valid options are:
`ck`, `md5`, `sha1`, `sha224`, `sha256`, `sha384`, `sha512`, and `b2`.
**STRIP_BINARIES=**"--strip-all"::
Options to be used when stripping binaries. See linkman:strip[1]
for details.
**STRIP_SHARED=**"--strip-unneeded"::
Options to be used when stripping shared libraries or PIE executables.
See linkman:strip[1] for details.
**STRIP_STATIC=**"--strip-debug"::
Options to be used when stripping static libraries. See linkman:strip[1]
for details.
**MAN_DIRS=(**{usr{,/local}{,/share},opt/*}/{man,info} ...**)**::
If `zipman` is specified in the `OPTIONS` array, this variable will
instruct makepkg where to look to compress manual (man and info)
pages. If you build packages that are located in opt/, you may need
to add the directory to this array. *NOTE:* Do not add the leading
slash to the directory name.
**DOC_DIRS=(**usr/{,share/}{doc,gtk-doc} ...**)**::
If `!docs` is specified in the `OPTIONS` array, this variable will
instruct makepkg where to look to remove docs. If you build packages
that are located in opt/, you may need to add the directory to this
array. *NOTE:* Do not add the leading slash to the directory name.
**LIB_DIRS=(**lib:usr/lib ...**)**::
If `autodeps` is specified in the `OPTIONS` array, this variable will
instruct makepkg where to look to find libraries to add to the `provides`
array. The format is "prefix:path", where provides will be added for
libraries found in "path" with the specified prefix added.
**PURGE_TARGETS=(**usr/{,share}/info/dir .podlist *.pod...**)**::
If `purge` is specified in the `OPTIONS` array, this variable will
instruct makepkg which files to remove from the package. This is
useful for index files that are added by multiple packages.
**DBGSRCDIR=**"/usr/src/debug"::
If `strip` and `debug` are specified in the `OPTIONS` array, this variable
will instruct makepkg where to place source files for installed binaries.
The binaries will be modified to link this directory for the debugger
search path.
**PKGDEST=**"/path/to/directory"::
If this value is not set, packages will, by default, be placed in the
current directory (location of the linkman:PKGBUILD[5]). Many people
like to keep all their packages in one place so this option allows
for this behavior. A common location is ``/home/packages''.
**SRCDEST=**"/path/to/directory"::
If this value is not set, downloaded source files will only be stored
in the current directory. Many people like to keep all source files in
a central location for easy cleanup, so this path can be set here.
**SRCPKGDEST=**"/path/to/directory"::
If this value is not set, source package files will be stored in
in the current directory. Many people like to keep all source package files
in a central location for easy cleanup, so this path can be set here.
**LOGDEST=**"/path/to/directory"::
If this value is not set, log files are written to the current
directory. This centralizes the log location, facilitating cleanup
and compression.
**PACKAGER=**"John Doe <john@example.com>"::
This value is used when querying a package to see who was the builder.
The given format is required for PGP key lookup through WKD.
It is recommended to change this to your name and email address.
**COMPRESSGZ=**"(gzip -c -f -n)"::
**COMPRESSBZ2=**"(bzip2 -c -f)"::
**COMPRESSXZ=**"(xz -c -z -)"::
**COMPRESSZST=**"(zstd -c -z -)"::
**COMPRESSLZO**"(lzop -q)"::
**COMPRESSLRZ=**"(lrzip -q)"::
**COMPRESSLZ4=**"(lz4 -q)"::
**COMPRESSZ=**"(compress -c -f)"::
**COMPRESSLZ=**"(lzip -c -f)"::
Sets the command and options used when compressing compiled or source
packages in the named format.
**PKGEXT=**"{pkgext}", **SRCEXT=**"{srcext}"::
Sets the compression used when making compiled or source packages.
Valid suffixes are `.pkg` or `.src` (for PKGEXT and SRCEXT respectively)
followed by one of `.tar.gz`, `.tar.bz2`, `.tar.xz`, `.tar.zst`, `.tar.lzo`,
`.tar.lrz`, `.tar.lz4`, `.tar.lz` and `.tar.Z`, or simply `.tar` to
disable compression entirely.
**PACMAN_AUTH=()**::
Specify a command prefix for running pacman as root. If unset, makepkg will
check for the presence of sudo(8) and su(1) in turn, and try the first one
it finds.
+
If present, `%c` will be replaced with the shell-quoted form of the command
to run. Otherwise, the command to run is appended to the auth command.
See Also
--------
linkman:makepkg[8], linkman:pacman[8], linkman:PKGBUILD[5]
include::footer.asciidoc[]

View file

@ -1,157 +0,0 @@
manpages = [
{ 'name': 'alpm-hooks.5' },
{ 'name': 'pacman.8' },
{ 'name': 'makepkg.8' },
{ 'name': 'makepkg-template.1' },
{ 'name': 'repo-add.8' },
{ 'name': 'vercmp.8' },
{ 'name': 'testpkg.8' },
{ 'name': 'pacman-key.8' },
{ 'name': 'pacman-db-upgrade.8' },
{ 'name': 'PKGBUILD.5', 'extra_depends' : [ 'PKGBUILD-example.txt' ] },
{ 'name': 'makepkg.conf.5' },
{ 'name': 'pacman.conf.5' },
{ 'name': 'BUILDINFO.5' },
{ 'name': 'pacman-conf.8' },
]
sitepages = [
{ 'name': 'submitting-patches' },
{ 'name': 'translation-help' },
{ 'name': 'HACKING', 'source': '../HACKING' },
{ 'name': 'index' },
]
asciidoc_conf = join_paths(meson.current_source_dir(), 'asciidoc.conf')
asciidoc_opts = [
'-f', asciidoc_conf,
'-a', 'pacman_version="@0@"'.format(PACKAGE_VERSION),
'-a', 'srcext=@0@'.format(get_option('src-ext')),
'-a', 'pkgext=@0@'.format(get_option('pkg-ext')),
'-a', 'pkgdatadir=@0@'.format(PKGDATADIR),
'-a', 'keyringdir=@0@'.format(KEYRINGDIR),
'-a', 'localstatedir=@0@'.format(LOCALSTATEDIR),
'-a', 'sysconfdir=@0@'.format(SYSCONFDIR),
'-a', 'datarootdir=@0@'.format(DATAROOTDIR),
'-a', 'rootdir=@0@'.format(ROOTDIR),
'-a', 'libmakepkgdir=@0@'.format(LIBMAKEPKGDIR),
]
html_targets = []
html_files = []
foreach page : manpages
manpage = page['name']
htmlpage = '@0@.html'.format(manpage)
input = '@0@.asciidoc'.format(manpage)
section = page['name'].split('.')[-1]
mandirn = join_paths(MANDIR, 'man' + section)
custom_target(
manpage,
command : [
A2X,
'--no-xmllint',
'-d', 'manpage',
'-f', 'manpage',
'--xsltproc-opts', '-param man.endnotes.list.enabled 0 -param man.endnotes.are.numbered 0',
'-D', '@OUTDIR@',
'--asciidoc-opts', ' '.join(asciidoc_opts),
'@INPUT@',
],
input : input,
output : [manpage],
depend_files : [
asciidoc_conf,
] + page.get('extra_depends', []),
install : true,
install_dir : mandirn,
)
endforeach
foreach page: manpages + sitepages
manpage = page['name']
htmlpage = '@0@.html'.format(manpage)
input = page.get('source', '@0@.asciidoc'.format(manpage))
html = custom_target(
htmlpage,
command : [
ASCIIDOC,
] + asciidoc_opts + [
'-a', 'linkcss',
'-a', 'toc',
'-a', 'icons',
'-a', 'max-width=960px',
'-a', 'stylesheet=asciidoc-override.css',
'-o', '@OUTPUT@',
'@INPUT@',
],
input : input,
output : [htmlpage],
depend_files : [
asciidoc_conf,
'asciidoc-override.css',
] + page.get('extra_depends', []),
build_by_default : false,
install : false,
)
html_targets += [html]
html_files += [htmlpage]
endforeach
run_target('html',
command : ['/bin/true'],
depends : html_targets)
custom_target(
'website.tar.gz',
command : [
'bsdtar', 'czf', '@OUTPUT@',
'-C', meson.current_build_dir(),
] + html_files + [
'-C', meson.current_source_dir(),
'asciidoc-override.css',
'-C', '/etc/asciidoc/stylesheets/',
'asciidoc.css',
'-C', '/etc/asciidoc/javascripts/',
'asciidoc.js',
'-C', '/etc/asciidoc/',
'images',
],
output : ['website.tar.gz'],
build_by_default : false,
depends : html_targets,
)
meson.add_install_script(MESON_MAKE_SYMLINK,
'repo-add.8',
join_paths(MANDIR, 'man8/repo-remove.8'))
meson.add_install_script(MESON_MAKE_SYMLINK,
'alpm-hooks.5',
join_paths(MANDIR, 'man5/pacman-hooks.5'))
doxygen = find_program('doxygen', required : get_option('doxygen'))
if doxygen.found() and not get_option('doxygen').disabled()
doxyconf = configuration_data()
doxyconf.set('INPUT_DIRECTORY', meson.current_source_dir())
doxyconf.set('OUTPUT_DIRECTORY', meson.current_build_dir())
doxyfile = configure_file(
input : 'Doxyfile.in',
output : 'Doxyfile',
configuration : doxyconf,
install : false)
custom_target(
'doxygen',
input : doxyfile,
output : ['man3'],
command : [doxygen, doxyfile],
build_by_default : true,
install : true,
install_dir : MANDIR)
endif

View file

@ -1,67 +0,0 @@
pacman-conf(8)
==============
Name
----
pacman-conf - query pacman's configuration file
Synopsis
--------
'pacman-conf' [options] [<directive> ...]
'pacman-conf' (--repo-list|--help|--version)
Description
-----------
'pacman-conf' is a utility for parsing the 'pacman' configuration file
and returning script-friendly output. It is designed to properly handle
non-trivial configuration features such as variable interpolation and
the use of the Include directive, and guarantees that it will return the
same configuration values which 'pacman' itself would use.
'pacman-conf' will output the fully-resolved contents of the
configuration file by default, or, if provided with the name of a
configuration directive, output the contents of the given directive alone.
Options
-------
*-c, \--config* <path>::
Specify an alternate configuration file.
*-R, \--rootdir* <path>::
Specify an alternate installation root (default is `/`).
*-r, \--repo* <repository>::
Query options for a specific repository.
*-v, \--verbose*::
Always shown directive names.
*-l, \--repo-list*::
List configured repositories.
*-h, \--help*::
Output syntax and command line options.
*-V, \--version*::
Display version and exit.
Examples
--------
pacman-conf -r core Usage::
Show the value of the Usage configuration option for core repository.
pacman-conf HoldPkg::
Show the value of the HoldPkg configuration option.
See Also
--------
linkman:pacman.conf[5]
include::footer.asciidoc[]

View file

@ -1,36 +0,0 @@
pacman-db-upgrade(8)
====================
Name
----
pacman-db-upgrade - upgrade the local pacman database to a newer format
Synopsis
--------
'pacman-db-upgrade' [options]
Description
-----------
'pacman-db-upgrade' is a script that upgrades the local database used
by linkman:pacman[8] to a newer format.
Options
--------------
*-h, \--help*::
Show the built-in help message and exit.
*-V, \--version*::
Show version information and exit.
*-d, \--dbpath* <path>::
Set an alternate database location.
*-r, \--root* <path>::
Set an alternate installation root.
*\--config* <path>::
Set an alternate configuration file.
*\--nocolor*::
Remove color from output.
See Also
--------
linkman:pacman[8]
include::footer.asciidoc[]

View file

@ -1,151 +0,0 @@
pacman-key(8)
=============
Name
----
pacman-key - manage pacman's list of trusted keys
Synopsis
--------
'pacman-key' [options] operation [targets]
Description
-----------
'pacman-key' is a wrapper script for GnuPG used to manage pacman's keyring, which
is the collection of PGP keys used to check signed packages and databases. It
provides the ability to import and export keys, fetch keys from keyservers and
update the key trust database.
More complex keyring management can be achieved using GnuPG directly combined with
the '\--homedir' option pointing at the pacman keyring (located in
+{sysconfdir}/pacman.d/gnupg+ by default).
Invoking pacman-key consists of supplying an operation with any potential
options and targets to operate on. Depending on the operation, a 'target' may
be a valid key identifier, filename, or directory.
Operations
----------
*-a, \--add*::
Add the key(s) contained in the specified file or files to pacman's
keyring. If a key already exists, update it.
*-d, \--delete*::
Remove the key(s) identified by the specified keyid(s) from pacman's
keyring.
*-e, \--export*::
Export key(s) identified by the specified keyid(s) to 'stdout'. If no keyid
is specified, all keys will be exported.
*\--edit-key*::
Present a menu for key management task on the specified keyid(s). Useful
for adjusting a keys trust level.
*-f, \--finger*::
List a fingerprint for each specified keyid, or for all known keys if no
keyids are specified.
*-h, \--help*::
Output syntax and command line options.
*\--import*::
Imports keys from `pubring.gpg` into the public keyring from the specified
directories.
*\--import-trustdb*::
Imports ownertrust values from `trustdb.gpg` into the shared trust database
from the specified directories.
*\--init*::
Ensure the keyring is properly initialized and has the required access
permissions.
*-l, \--list-keys*::
Lists all or specified keys from the public keyring.
*\--list-sigs*::
Same as '\--list-keys', but the signatures are listed too.
*\--lsign-key*::
Locally sign the given key. This is primarily used to root the web of trust
in the local private key generated by '\--init'.
*\--nocolor*::
Disable colored output from pacman-key.
*-r, \--recv-keys*::
Equivalent to '\--recv-keys' in GnuPG.
*\--refresh-keys*::
Equivalent to '\--refresh-keys' in GnuPG.
*\--populate*::
Reload the default keys from the (optionally provided) keyrings in
+{keyringdir}+. For more information, see
<<PK,Providing a Keyring for Import>> below.
*-u, \--updatedb*::
Equivalent to '\--check-trustdb' in GnuPG. This operation can be specified with
other operations.
*-V, \--version*::
Displays the program version.
*-v, \--verify*::
Assume that the first argument is a signature and verify it. If a second
argument is provided, it is the file to be verified.
+
With only one argument given, assume that the signature is a detached
signature, and look for a matching data file to verify by stripping the file
extension. If no matching data file is found, fall back on GnuPG semantics and
attempt to verify a file with an embedded signature.
Options
-------
*\--config* <file>::
Use an alternate configuration file instead of the +{sysconfdir}/pacman.conf+
default.
*\--gpgdir* <dir>::
Set an alternate home directory for GnuPG. If unspecified, the value is
read from +{sysconfdir}/pacman.conf+.
*\--keyserver* <keyserver>::
Use the specified keyserver if the operation requires one. This will take
precedence over any keyserver option specified in a `gpg.conf`
configuration file. Running '\--init' with this option will set the default
keyserver if one was not already configured.
Providing a Keyring for Import[[PK]]
------------------------------------
A distribution or other repository provided may want to provide a set of
PGP keys used in the signing of its packages and repository databases that can
be readily imported into the pacman keyring. This is achieved by providing a
PGP keyring file `foo.gpg` that contains the keys for the foo keyring in the
directory +{keyringdir}+.
Optionally, the file `foo-trusted` can be provided containing a list of trusted
key IDs for that keyring. This is a file in a format compatible with 'gpg
\--export-ownertrust' output. This file will inform the user which keys a user
needs to verify and sign to build a local web of trust, in addition to
assigning provided owner trust values.
Also optionally, the file `foo-revoked` can be provided containing a list of
revoked key IDs for that keyring. Revoked is defined as "no longer valid for
any signing", so should be used with prudence. A key being marked as revoked
will be disabled in the keyring and no longer treated as valid, so this always
takes priority over it's trusted state in any other keyring.
See Also
--------
linkman:pacman[8], linkman:pacman.conf[5]
include::footer.asciidoc[]

View file

@ -1,583 +0,0 @@
pacman(8)
=========
Name
----
pacman - package manager utility
Synopsis
--------
'pacman' <operation> [options] [targets]
Description
-----------
Pacman is a package management utility that tracks installed packages on a Linux
system. It features dependency support, package groups, install and uninstall
scripts, and the ability to sync your local machine with a remote repository to
automatically upgrade packages. Pacman packages are a zipped tar format.
Since version 3.0.0, pacman has been the front-end to linkman:libalpm[3], the
``Arch Linux Package Management'' library. This library allows alternative
front-ends to be written (for instance, a GUI front-end).
Invoking pacman involves specifying an operation with any potential options and
targets to operate on. A 'target' is usually a package name, file name, URL, or
a search string. Targets can be provided as command line arguments.
Additionally, if stdin is not from a terminal and a single hyphen (-) is passed
as an argument, targets will be read from stdin.
Operations
----------
*-D, \--database*::
Operate on the package database. This operation allows you to modify
certain attributes of the installed packages in pacman's database. It
also allows you to check the databases for internal consistency.
See <<DO,Database Options>> below.
*-Q, \--query*::
Query the package database. This operation allows you to view installed
packages and their files, as well as meta-information 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 package files. In the first case, if no package names
are provided in the command line, all installed packages will be
queried. Additionally, various filters can be applied on the package
list. See <<QO,Query Options>> below.
*-R, \--remove*::
Remove package(s) from the system. Groups can also be specified to be
removed, in which case every package in that group will be removed.
Files belonging to the specified package will be deleted, and the
database will be updated. Most configuration files will be saved
with a '.pacsave' extension unless the '\--nosave' option is used.
See <<RO,Remove Options>> below.
*-S, \--sync*::
Synchronize packages. Packages are installed directly from the remote
repositories, including all dependencies required to run the packages. For
example, `pacman -S qt` will download and install qt and all the
packages it depends on. If a package name exists in more than one
repository, the repository can be explicitly specified to clarify the
package to install: `pacman -S testing/qt`. You can also specify version
requirements: `pacman -S "bash>=3.2"`. Quotes are needed, otherwise the
shell interprets ">" as redirection to a file.
+
In addition to packages, groups can be specified as well. For example, if
gnome is a defined package group, then `pacman -S gnome` will provide a
prompt allowing you to select which packages to install from a numbered list.
The package selection is specified using a space- and/or comma-separated list of
package numbers. Sequential packages may be selected by specifying the first
and last package numbers separated by a hyphen (`-`). Excluding packages is
achieved by prefixing a number or range of numbers with a caret (`^`).
+
Packages that provide other packages are also handled. For example, `pacman -S
foo` will first look for a foo package. If foo is not found, packages that
provide the same functionality as foo will be searched for. If any package is
found, it will be installed. A selection prompt is provided if multiple packages
providing foo are found.
+
You can also use `pacman -Su` to upgrade all packages that are out-of-date. See
<<SO,Sync Options>> below. When upgrading, pacman performs version comparison
to determine which packages need upgrading. This behavior operates as follows:
Alphanumeric:
1.0a < 1.0b < 1.0beta < 1.0p < 1.0pre < 1.0rc < 1.0 < 1.0.a < 1.0.1
Numeric:
1 < 1.0 < 1.1 < 1.1.1 < 1.2 < 2.0 < 3.0.0
+
Additionally, version strings can have an 'epoch' value defined that will
overrule any version comparison, unless the epoch values are equal. This is
specified in an `epoch:version-rel` format. For example, `2:1.0-1` is always
greater than `1:3.6-1`.
*-T, \--deptest*::
Check dependencies; this is useful in scripts such as makepkg to check
installed packages. This operation will check each dependency specified and
return a list of dependencies that are not currently satisfied on the system.
This operation accepts no other options. Example usage: `pacman -T qt
"bash>=3.2"`.
*-U, \--upgrade*::
Upgrade or add package(s) to the system and install the required
dependencies from sync repositories. Either a URL or file path can be
specified. This is a ``remove-then-add'' process. See <<UO,Upgrade
Options>> below; also see <<HCF,Handling Config Files>> for an explanation
on how pacman takes care of configuration files.
*-F, \--files*::
Query the files database. This operation allows you to look for packages
owning certain files or display files owned by certain packages. Only
packages that are part of your sync databases are searched. See
<<FO,File Options>> below.
*-V, \--version*::
Display version and exit.
*-h, \--help*::
Display syntax for the given operation. If no operation was supplied,
then the general syntax is shown.
Options
-------
*-b, \--dbpath* <path>::
Specify an alternative database location (the default is
+{localstatedir}/lib/pacman+). This should not be used unless you know what
you are doing.
*NOTE*: If specified, this is an absolute path, and the root path is
not automatically prepended.
*-r, \--root* <path>::
Specify an alternative installation root (default is +{rootdir}+). This should
not be used as a way to install software into `/usr/local` instead of
`/usr`.
*NOTE*: If database path or log file are not specified on either the
command line or in linkman:pacman.conf[5], their default location will
be inside this root path.
*NOTE*: This option is not suitable for performing operations on a mounted
guest system. See '\--sysroot' instead.
*-v, \--verbose*::
Output paths such as the Root, Conf File, DB Path, Cache Dirs, etc.
*\--arch* <arch>::
Specify an alternate architecture.
*\--cachedir* <dir>::
Specify an alternative package cache location (the default is
+{localstatedir}/cache/pacman/pkg+). Multiple cache directories can be
specified, and they are tried in the order they are passed to pacman.
*NOTE*: This is an absolute path, and the root path is not automatically
prepended. If DownloadUser is set in linkman:pacman.conf[5], then the
specified user must have permission to access the cache directory.
*\--color* <when>::
Specify when to enable coloring. Valid options are 'always', 'never', or
'auto'. 'always' forces colors on; 'never' forces colors off; and 'auto' only
automatically enables colors when outputting onto a tty.
*\--config* <file>::
Specify an alternate configuration file.
*\--debug*::
Display debug messages. When reporting bugs, this option is recommended
to be used.
*\--gpgdir* <dir>::
Specify a directory of files used by GnuPG to verify package signatures
(the default is +{sysconfdir}/pacman.d/gnupg+). This directory should contain
two files: `pubring.gpg` and `trustdb.gpg`. `pubring.gpg` holds the public keys
of all packagers. `trustdb.gpg` contains a so-called trust database, which
specifies that the keys are authentic and trusted. *NOTE*: This is an absolute
path, and the root path is not automatically prepended.
*\--hookdir* <dir>::
Specify a alternative directory containing hook files (the default is
+{sysconfdir}/pacman.d/hooks+). Multiple hook directories can be specified
with hooks in later directories taking precedence over hooks in earlier
directories. *NOTE*: This is an absolute path, and the root path is not
automatically prepended.
*\--logfile* <file>::
Specify an alternate log file. This is an absolute path, regardless of
the installation root setting.
*\--noconfirm*::
Bypass any and all ``Are you sure?'' messages. It's not a good idea to do
this unless you want to run pacman from a script.
*\--confirm*::
Cancels the effects of a previous '\--noconfirm'.
*\--disable-download-timeout*::
Disable defaults for low speed limit and timeout on downloads. Use this
if you have issues downloading files with proxy and/or security gateway.
*\--sysroot* <dir>:: Specify an alternative system root. This path will be
prepended to all other configuration directories and any repository servers
beginning with `file://`. Any paths or URLs passed as targets will not be
modified. This allows mounted guest systems to be properly operated on.
*\--disable-sandbox*::
Disable the default sandbox applied to the process downloading files on Linux
systems. Useful if experiencing landlock related failures while downloading
files when running a Linux kernel that does not support this feature.
Transaction Options (apply to '-S', '-R' and '-U')
--------------------------------------------------
*-d, \--nodeps*::
Skips dependency version checks. Package names are still checked. 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. Specify this option twice to skip all dependency checks.
*\--assume-installed* <package=version>::
Add a virtual package "package" with version "version" to the transaction
to satisfy dependencies. This allows disabling the specific dependency checks
without affecting all dependency checks. To disable all dependency
checking, see the '\--nodeps' option.
*\--dbonly*::
Adds/removes the database entry only, leaving all files in place.
*\--noprogressbar*::
Do not show a progress bar when downloading files. This can be useful
for scripts that call pacman and capture the output.
*\--noscriptlet*::
If an install scriptlet exists, do not execute it. Do not use this
unless you know what you are doing.
*-p, \--print*::
Only print the targets instead of performing the actual operation (sync,
remove or upgrade). Use '\--print-format' to specify how targets are
displayed. The default format string is "%l", which displays URLs with
'-S', file names with '-U', and pkgname-pkgver with '-R'.
*\--print-format* <format>::
Specify a printf-like format to control the output of the '\--print'
operation. The possible attributes are: "%a" for arch, "%b" for
builddate, "%d" for description, "%e" for pkgbase, "%f" for filename,
"%g" for base64 encoded PGP signature, "%h" for sha256sum, "%m" for
md5sum, "%n" for pkgname, "%p" for packager, "%v" for pkgver, "%l" for
location, "%r" for repository, "%s" for size, "%C" for checkdepends,
"%D" for depends, "%G" for groups, "%H" for conflicts, "%L" for
licenses, "%M" for makedepends, "%O" for optional depends, "%P" for
provides and "%R" for replaces.
Implies '\--print'.
Upgrade Options (apply to '-S' and '-U')[[UO]]
----------------------------------------------
*-w, \--downloadonly*::
Retrieve all packages from the server, but do not install/upgrade anything.
*\--asdeps*::
Install packages non-explicitly; in other words, fake their install reason
to be installed as a dependency. This is useful for makepkg and other
build-from-source tools that need to install dependencies before building
the package.
*\--asexplicit*::
Install packages explicitly; in other words, fake their install reason to
be explicitly installed. This is useful if you want to mark a dependency
as explicitly installed so it will not be removed by the '\--recursive'
remove operation.
*\--ignore* <package>::
Directs pacman to ignore upgrades of package even if there is one
available. Multiple packages can be specified by separating them
with a comma.
*\--ignoregroup* <group>::
Directs pacman to ignore upgrades of all packages in 'group', even if
there is one available. Multiple groups can be specified by
separating them with a comma.
*\--needed*::
Do not reinstall the targets that are already up-to-date.
*\--overwrite* <glob>::
Bypass file conflict checks and overwrite conflicting files. If the
package that is about to be installed contains files that are already
installed and match 'glob', this option will cause all those files to be
overwritten. Using '\--overwrite' will not allow overwriting a directory
with a file or installing packages with conflicting files and directories.
Multiple patterns can be specified by separating them with a comma. May be
specified multiple times. Patterns can be negated, such that files
matching them will not be overwritten, by prefixing them with an
exclamation mark. Subsequent matches will override previous ones. A leading
literal exclamation mark or backslash needs to be escaped.
Query Options (apply to '-Q')[[QO]]
-----------------------------------
*-c, \--changelog*::
View the ChangeLog of a package if it exists.
*-d, \--deps*::
Restrict or filter output to packages installed as dependencies. This
option can be combined with '-t' for listing real orphans - packages that
were installed as dependencies but are no longer required by any
installed package.
*-e, \--explicit*::
Restrict or filter output to explicitly installed packages. This option
can be combined with '-t' to list explicitly installed packages that
are not required by any other package.
*-g, \--groups*::
Display all packages that are members of a named group. If a name is not
specified, list all grouped packages.
*-i, \--info*::
Display information on a given package. The '-p' option can be used if
querying a package file instead of the local database. Passing two
'\--info' or '-i' flags will also display the list of backup files and
their modification states.
*-k, \--check*::
Check that all files owned by the given package(s) are present on the
system. If packages are not specified or filter flags are not provided,
check all installed packages. Specifying this option twice will perform
more detailed file checking (including permissions, file sizes, and
modification times) for packages that contain the needed mtree file.
*-l, \--list*::
List all files owned by a given package. Multiple packages can be
specified on the command line.
*-m, \--foreign*::
Restrict or filter output to packages that were not found in the sync
database(s). Typically these are packages that were downloaded manually
and installed with '\--upgrade'.
*-n, \--native*::
Restrict or filter output to packages that are found in the sync
database(s). This is the inverse filter of '\--foreign'.
*-o, \--owns* <file>::
Search for packages that own the specified file(s). The path can be
relative or absolute, and one or more files can be specified.
*-p, \--file*::
Signifies that the package supplied on the command line is a file and
not an entry in the database. The file will be decompressed and queried.
This is useful in combination with '\--info' and '\--list'.
*-q, \--quiet*::
Show less information for certain query operations. This is useful when
pacman's output is processed in a script. Search will only show package
names and not version, group, and description information; owns will
only show package names instead of "file is owned by pkg" messages; group
will only show package names and omit group names; list will only show
files and omit package names; check will only show pairs of package names
and missing files; a bare query will only show package names
rather than names and versions.
*-s, \--search* <regexp>::
Search each locally-installed package for names or descriptions that
match `regexp`. When including multiple search terms, only packages
with descriptions matching ALL of those terms are returned.
*-t, \--unrequired*::
Restrict or filter output to print only packages neither required nor
optionally required by any currently installed package. Specify this
option twice to include packages which are optionally, but not directly,
required by another package.
*-u, \--upgrades*::
Restrict or filter output to packages that are out-of-date on the local
system. Only package versions are used to find outdated packages;
replacements are not checked here. This option works best if the sync
database is refreshed using '-Sy'.
Remove Options (apply to '-R')[[RO]]
------------------------------------
*-c, \--cascade*::
Remove all target packages, as well as all packages that depend on one
or more target packages. This operation is recursive and must be used
with care, since it can remove many potentially needed packages.
*-n, \--nosave*::
Instructs pacman to ignore file backup designations. Normally, when a
file is removed from the system, the database is checked to see if the
file should be renamed with a '.pacsave' extension.
*-s, \--recursive*::
Remove each target specified including all of their dependencies, provided
that (A) they are not required by other packages; and (B) they were not
explicitly installed by the user. This operation is recursive and analogous
to a backwards '\--sync' operation, and it helps keep a clean system without
orphans. If you want to omit condition (B), pass this option twice.
*-u, \--unneeded*::
Removes targets that are not required by any other packages.
This is mostly useful when removing a group without using the '-c' option,
to avoid breaking any dependencies.
Sync Options (apply to '-S')[[SO]]
----------------------------------
*-c, \--clean*::
Remove packages that are no longer installed from the cache as well as
currently unused sync databases to free up disk space. When pacman
downloads packages, it saves them in a cache directory. In addition,
databases are saved for every sync DB you download from and are not
deleted even if they are removed from the configuration file
linkman:pacman.conf[5]. Use one '\--clean' switch to only remove
packages that are no longer installed; use two to remove all files
from the cache. In both cases, you will have a yes or no option to
remove packages and/or unused downloaded databases.
+
If you use a network shared cache, see the 'CleanMethod' option in
linkman:pacman.conf[5].
*-g, \--groups*::
Display all the members for each package group specified. If no group
names are provided, all groups will be listed; pass the flag twice to
view all groups and their members.
*-i, \--info*::
Display information on a given sync database package. Passing two '\--info'
or '-i' flags will also display those packages in all repositories that
depend on this package.
*-l, \--list*::
List all packages in the specified repositories. Multiple repositories
can be specified on the command line.
*-q, \--quiet*::
Show less information for certain sync operations. This is useful when
pacman's output is processed in a script. Search will only show package
names and not repository, version, group, and description information; list
will only show package names and omit databases and versions; group will
only show package names and omit group names.
*-s, \--search* <regexp>::
This will search each package in the sync databases for names or
descriptions that match `regexp`. When you include multiple search
terms, only packages with descriptions matching ALL of those terms will
be returned.
*-u, \--sysupgrade*::
Upgrades all packages that are out-of-date. Each currently-installed
package will be examined and upgraded if a newer package exists. A
report of all packages to upgrade will be presented, and the operation
will not proceed without user confirmation. Dependencies are
automatically resolved at this level and will be installed/upgraded if
necessary.
+
Pass this option twice to enable package downgrades; in this case, pacman will
select sync packages whose versions do not match with the local versions. This
can be useful when the user switches from a testing repository to a stable one.
+
Additional targets can also be specified manually, so that '-Su foo' will do a
system upgrade and install/upgrade the "foo" package in the same operation.
*-y, \--refresh*::
Download a fresh copy of the master package databases '(repo.db)' from the
server(s) defined in linkman:pacman.conf[5]. This should typically be used
each time you use '\--sysupgrade' or '-u'. Passing two '\--refresh' or '-y'
flags will force a refresh of all package databases, even if they appear to
be up-to-date.
Database Options (apply to '-D')[[QO]]
--------------------------------------
*\--asdeps* <package>::
Mark a package as non-explicitly installed; in other words, set their install
reason to be installed as a dependency.
*\--asexplicit* <package>::
Mark a package as explicitly installed; in other words, set their install
reason to be explicitly installed. This is useful if you want to keep a
package installed even when it was initially installed as a dependency
of another package.
*-k, \--check*::
Check the local package database is internally consistent. This will
check all required files are present and that installed packages have
the required dependencies, do not conflict and that multiple packages
do not own the same file. Specifying this option twice will perform
a check on the sync databases to ensure all specified dependencies
are available.
*-q, \--quiet*::
Suppress messages on successful completion of database operations.
File Options (apply to '-F')[[FO]]
----------------------------------
*-y, --refresh*::
Download fresh package file databases '(repo.files)' from the server.
Use twice to force a refresh even if databases are up to date.
*-l, \--list*::
List the files owned by the queried package.
*-x, --regex*::
Interpret each query as a regular expression.
*-q, \--quiet*::
Show less information for certain file operations. This is useful when
pacman's output is processed in a script, however, you may want to use
'--machinereadable' instead.
*--machinereadable*::
Print each match in a machine readable output format. The format is
'repository\0pkgname\0pkgver\0path\n' with '\0' being the NULL character
and '\n' a linefeed.
Handling Config Files[[HCF]]
----------------------------
Pacman uses the same logic as 'rpm' to determine action against files that are
designated to be backed up. During an upgrade, three MD5 hashes are used for
each backup file to determine the required action: one for the original file
installed, one for the new file that is about to be installed, and one for the
actual file existing on the file system. After comparing these three hashes, the
following scenarios can result:
original=X, current=X, new=X::
All three files are the same, so overwrites are not an issue. Install the
new file.
original=X, current=X, new=Y::
The current file is the same as the original, but the new one differs.
Since the user did not ever modify the file, and the new one may contain
improvements or bug fixes, install the new file.
original=X, current=Y, new=X::
Both package versions contain the exact same file, but the one on the
file system has been modified. Leave the current file in place.
original=X, current=Y, new=Y::
The new file is identical to the current file. Install the new file.
original=X, current=Y, new=Z::
All three files are different, so install the new file with a '.pacnew'
extension and warn the user. The user must then manually merge any
necessary changes into the original file.
original=NULL, current=Y, new=Z::
The package was not previously installed, and the file already exists on the
file system. Install the new file with a '.pacnew' extension and warn the
user. The user must then manually merge any necessary changes into the
original file.
Examples
--------
pacman -Ss ne.hack::
Search for regexp "ne.hack" in package database.
pacman -S gpm::
Download and install gpm including dependencies.
pacman -U /home/user/ceofhack-0.6-1-x86_64.pkg.tar.gz::
Install ceofhack-0.6-1 package from a local file.
pacman -Syu::
Update package list and upgrade all packages afterwards.
pacman -Syu gpm::
Update package list, upgrade all packages, and then install gpm if it
wasn't already installed.
Configuration
-------------
See linkman:pacman.conf[5] for more details on configuring pacman using the
'pacman.conf' file.
See Also
--------
linkman:alpm-hooks[5], linkman:libalpm[3], linkman:makepkg[8],
linkman:pacman.conf[5]
include::footer.asciidoc[]

327
doc/pacman.8.in Normal file
View file

@ -0,0 +1,327 @@
.TH pacman 8 "January 21, 2006" "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 idea to do this
unless you want to run pacman from a script.
.TP
.B "\-\-noprogressbar"
Do not show a progress bar when downloading files. This can be useful for
scripts that call pacman and capture the output.
.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 package that will be installed, including any
dependencies that have yet to be installed. These can be piped to a
file and downloaded at a later time, using a program like wget.
.TP
.B "\-s, \-\-search <regexp>"
This will search each package in the package list for names or descriptions
that matches <regexp>.
.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 "\-m, \-\-foreign"
List all packages that were not found in the sync database(s). Typically these
are packages that were downloaded manually and installed with --add.
.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 <regexp>"
This will search each locally-installed package for names or descriptions
that matches <regexp>.
.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 with a .pacnew
extension and warn the user, so she can manually move the file into place
after making any necessary customizations.
.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 "NoExtract = <file> [file] ..."
All files listed with a \fBNoExtract\fP directive will never be extracted from
a package into the filesystem. This can be useful when you don't want part of
a package to be installed. For example, if your httpd root uses an index.php,
then you would not want the index.html file to be extracted from the apache
package.
.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

View file

@ -1,382 +0,0 @@
pacman.conf(5)
==============
Name
----
pacman.conf - pacman package manager configuration file
Synopsis
--------
{sysconfdir}/pacman.conf
Description
-----------
Pacman, using linkman:libalpm[3], will attempt to read pacman.conf each time it
is invoked. This configuration file is divided into sections or repositories.
Each section defines a package repository that pacman can use when searching
for packages in '\--sync' mode. The exception to this is the options section,
which defines global options.
Comments are only supported by beginning a line with the hash (#) symbol.
Comments cannot begin in the middle of a line.
Example
-------
--------
#
# pacman.conf
#
[options]
NoUpgrade = etc/passwd etc/group etc/shadow
NoUpgrade = etc/fstab
[core]
Include = /etc/pacman.d/core
[custom]
Server = file:///home/pkgs
--------
NOTE: Each directive must be in CamelCase. If the case isn't respected, the
directive won't be recognized. For example. noupgrade or NOUPGRADE will not
work.
Options
-------
*RootDir =* /path/to/root/dir::
Set the default root directory for pacman to install to. This option is
used if you want to install a package on a temporary mounted partition
which is "owned" by another system, or for a chroot install.
*NOTE*: If database path or log file are not specified on either the
command line or in linkman:pacman.conf[5], their default location will
be inside this root path.
*DBPath =* /path/to/db/dir::
Overrides the default location of the toplevel database directory. The
default is +{localstatedir}/lib/pacman/+. Most users will not need to set
this option. *NOTE*: if specified, this is an absolute path and the root
path is not automatically prepended.
*CacheDir =* /path/to/cache/dir::
Overrides the default location of the package cache directory. The
default is +{localstatedir}/cache/pacman/pkg/+. Multiple cache directories can be
specified, and they are tried in the order they are listed in the config
file. If a file is not found in any cache directory, it will be downloaded
to the first cache directory with write access. *NOTE*: this is an absolute
path, the root path is not automatically prepended.
*HookDir =* /path/to/hook/dir::
Add directories to search for alpm hooks in addition to the system hook
directory (+{datarootdir}/libalpm/hooks/+). The default is
+{sysconfdir}/pacman.d/hooks+. Multiple directories can be specified with
hooks in later directories taking precedence over hooks in earlier
directories. *NOTE*: this is an absolute path, the root path is not
automatically prepended. For more information on the alpm hooks, see
linkman:alpm-hooks[5].
*GPGDir =* /path/to/gpg/dir::
Overrides the default location of the directory containing configuration
files for GnuPG. The default is +{sysconfdir}/pacman.d/gnupg/+.
This directory should contain two files: `pubring.gpg` and `trustdb.gpg`.
`pubring.gpg` holds the public keys of all packagers. `trustdb.gpg`
contains a so-called trust database, which specifies that the keys are
authentic and trusted.
*NOTE*: this is an absolute path, the root path is not automatically
prepended.
*LogFile =* /path/to/log/file::
Overrides the default location of the pacman log file. The default
is +{localstatedir}/log/pacman.log+. This is an absolute path and the root directory
is not prepended.
*HoldPkg =* package ...::
If a user tries to '\--remove' a package that's listed in `HoldPkg`,
pacman will ask for confirmation before proceeding. Shell-style glob
patterns are allowed.
*IgnorePkg =* package ...::
Instructs pacman to ignore any upgrades for this package when performing
a '\--sysupgrade'. Shell-style glob patterns are allowed.
*IgnoreGroup =* group ...::
Instructs pacman to ignore any upgrades for all packages in this
group when performing a '\--sysupgrade'. Shell-style glob patterns are
allowed.
*Include =* /path/to/config/file::
Include another configuration file. This file can include repositories or
general configuration options. Wildcards in the specified paths will get
expanded based on linkman:glob[7] rules.
*Architecture =* auto &| i686 &| x86_64 | ...::
If set, pacman will only allow installation of packages with the given
architectures (e.g. 'i686', 'x86_64', etc). The special value 'auto' will
use the system architecture, provided via ``uname -m''. If unset, no
architecture checks are made. *NOTE*: Packages with the special
architecture 'any' can always be installed, as they are meant to be
architecture independent.
*XferCommand =* /path/to/command %u [%o]::
If set, an external program will be used to download all remote files.
All instances of `%u` will be replaced with the download URL. If present,
instances of `%o` 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 built-in
HTTP/FTP support, or need the more advanced proxy support that comes with
utilities like wget.
*NoUpgrade =* file ...::
All files listed with a `NoUpgrade` directive will never be touched during
a package install/upgrade, and the new files will be installed with a
'.pacnew' extension.
These files refer to files in the package archive, so do not include the
leading slash (the RootDir) when specifying them. Shell-style glob patterns
are allowed. It is possible to invert matches by prepending a file with
an exclamation mark. Inverted files will result in previously blacklisted
files being whitelisted again. Subsequent matches will override previous
ones. A leading literal exclamation mark or backslash needs to be escaped.
*NoExtract =* file ...::
All files listed with a `NoExtract` directive will never be extracted from
a package into the filesystem. This can be useful when you don't want part
of a package to be installed. For example, if your httpd root uses an
'index.php', then you would not want the 'index.html' file to be extracted
from the 'apache' package.
These files refer to files in the package archive, so do not include the
leading slash (the RootDir) when specifying them. Shell-style glob patterns
are allowed. It is possible to invert matches by prepending a file with
an exclamation mark. Inverted files will result in previously blacklisted
files being whitelisted again. Subsequent matches will override previous
ones. A leading literal exclamation mark or backslash needs to be escaped.
*CleanMethod =* KeepInstalled &| KeepCurrent::
If set to `KeepInstalled` (the default), the '-Sc' operation will clean
packages that are no longer installed (not present in the local database).
If set to `KeepCurrent`, '-Sc' will clean outdated packages (not present in
any sync database).
The second behavior is useful when the package cache is shared among
multiple machines, where the local databases are usually different, but the
sync databases in use could be the same. If both values are specified,
packages are only cleaned if not installed locally and not present in any
known sync database.
*SigLevel =* ...::
Set the default signature verification level. For more information, see
<<SC,Package and Database Signature Checking>> below.
*LocalFileSigLevel =* ...::
Set the signature verification level for installing packages using the "-U"
operation on a local file. Uses the value from SigLevel as the default.
*RemoteFileSigLevel =* ...::
Set the signature verification level for installing packages using the "-U"
operation on a remote file URL. Uses the value from SigLevel as the default.
*UseSyslog*::
Log action messages through syslog(). This will insert log entries into
+{localstatedir}/log/messages+ or equivalent.
*Color*::
Automatically enable colors only when pacman's output is on a tty.
*NoProgressBar*::
Disables progress bars. This is useful for terminals which do
not support escape characters.
*CheckSpace*::
Performs an approximate check for adequate available disk space before
installing packages.
*VerbosePkgLists*::
Displays name, version and size of target packages formatted
as a table for upgrade, sync and remove operations.
*DisableDownloadTimeout*::
Disable defaults for low speed limit and timeout on downloads. Use this
if you have issues downloading files with proxy and/or security gateway.
*ParallelDownloads =* ...::
Specifies number of concurrent download streams. The value needs to be a
positive integer. If this config option is not set then only one download
stream is used (i.e. downloads happen sequentially).
*DownloadUser =* username::
Specifies the user to switch to for downloading files. If this config
option is not set then the downloads are done as the user running pacman.
*DisableSandbox*::
Disable the default sandbox applied to the process downloading files on Linux
systems. Useful if experiencing landlock related failures while downloading
files when running a Linux kernel that does not support this feature.
Repository Sections
-------------------
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 (the two above are 'core' and 'custom'). Repository names
must be unique and the name 'local' is reserved for the database of installed
packages. Locations are defined with the 'Server' directive and follow a URL
naming structure. If you want to use a local directory, you can specify the
full path with a ``file://'' prefix, as shown above.
A common way to define DB locations utilizes the 'Include' directive. For each
repository defined in the configuration file, a single 'Include' directive can
contain a file that lists the servers for that repository.
--------
[core]
# use this server first
Server = ftp://ftp.archlinux.org/$repo/os/$arch
# next use servers as defined in the mirrorlist below
Include = /etc/pacman.d/mirrorlist
--------
The order of repositories in the configuration files matters; repositories
listed first will take precedence over those listed later in the file when
packages in two repositories have identical names, regardless of version
number.
*Include =* path::
Include another config file. This file can include repositories or
general configuration options. Wildcards in the specified paths will get
expanded based on linkman:glob[7] rules.
*CacheServer =* url::
A full URL to a location where the packages, and signatures (if
available) for this repository can be found. Cache servers will be tried
before any non-cache servers, will not be removed from the server pool for
404 download errors, and will not be used for database files.
*Server =* url::
A full URL to a location where the database, packages, and signatures (if
available) for this repository can be found.
+
During parsing, pacman will define the `$repo` variable to the name of the
current section. This is often utilized in files specified using the 'Include'
directive so all repositories can use the same mirrorfile. pacman also defines
the `$arch` variable to the first (or only) value of the `Architecture` option,
so the same mirrorfile can even be used for different architectures.
*SigLevel =* ...::
Set the signature verification level for this repository. For more
information, see <<SC,Package and Database Signature Checking>> below.
*Usage =* ...::
Set the usage level for this repository. This option takes a list of tokens
which must be at least one of the following:
*Sync*;;
Enables refreshes for this repository.
*Search*;;
Enables searching for this repository.
*Install*;;
Enables installation of packages from this repository during a '\--sync'
operation.
*Upgrade*;;
Allows this repository to be a valid source of packages when performing
a '\--sysupgrade'.
*All*;;
Enables all of the above features for the repository. This is the default
if not specified.
+
Note that an enabled repository can be operated on explicitly, regardless of the Usage
level set.
Package and Database Signature Checking[[SC]]
---------------------------------------------
The 'SigLevel' directive is valid in both the `[options]` and repository
sections. If used in `[options]`, it sets a default value for any repository
that does not provide the setting.
* If set to *Never*, no signature checking will take place.
* If set to *Optional* , signatures will be checked when present, but unsigned
databases and packages will also be accepted.
* If set to *Required*, signatures will be required on all packages and
databases.
Alternatively, you can get more fine-grained control by combining some of
the options and prefixes described below. All options in a config file are
processed in top-to-bottom, left-to-right fashion, where later options override
and/or supplement earlier ones. If 'SigLevel' is specified in a repository
section, the starting value is that from the `[options]` section, or the
built-in system default as shown below if not specified.
The options are split into two main groups, described below. Terms used such as
``marginally trusted'' are terms used by GnuPG, for more information please
consult linkman:gpg[1].
When to Check::
These options control if and when signature checks should take place.
*Never*;;
All signature checking is suppressed, even if signatures are present.
*Optional* (default);;
Signatures are checked if present; absence of a signature is not an
error. An invalid signature is a fatal error, as is a signature from a
key not in the keyring.
*Required*;;
Signatures are required; absence of a signature or an invalid signature
is a fatal error, as is a signature from a key not in the keyring.
What is Allowed::
These options control what signatures are viewed as permissible. Note that
neither of these options allows acceptance of invalid or expired
signatures, or those from revoked keys.
*TrustedOnly* (default);;
If a signature is checked, it must be in the keyring and fully trusted;
marginal trust does not meet this criteria.
*TrustAll*;;
If a signature is checked, it must be in the keyring, but is not
required to be assigned a trust level (e.g., unknown or marginal
trust).
Options in both groups can additionally be prefixed with either *Package* or
*Database*, which will cause it to only take effect on the specified object
type. For example, `PackageTrustAll` would allow marginal and unknown trust
level signatures for packages.
The built-in default is the following:
--------
SigLevel = Optional TrustedOnly
--------
Using Your Own Repository
-------------------------
If you have numerous custom packages of your own, it is often easier to generate
your own custom local repository than install them all with the '\--upgrade'
option. All you need to do is generate a compressed package database in the
directory with these packages so pacman can find it when run with '\--refresh'.
repo-add /home/pkgs/custom.db.tar.gz /home/pkgs/*.pkg.tar.gz
The above command will generate a compressed database named
'/home/pkgs/custom.db.tar.gz'. Note that the database must be of the form
'\{treename\}.db.tar.{ext}', where '\{treename\}' is the name of the section
defined in the configuration file and '\{ext\}' is a valid compression type as
documented in linkman:repo-add[8]. That's it! Now configure your custom 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.
For more information on the repo-add command, see ``repo-add \--help'' or
linkman:repo-add[8].
See Also
--------
linkman:pacman[8], linkman:libalpm[3]
include::footer.asciidoc[]

View file

@ -1,95 +0,0 @@
repo-add(8)
==========
Name
----
repo-add - package database maintenance utility
Synopsis
--------
'repo-add' [options] <path-to-db> <package> [<package> ...]
'repo-remove' [options] <path-to-db> <packagename> [<packagename> ...]
Description
-----------
'repo-add' and 'repo-remove' are two scripts to help build a package database for
packages built with linkman:makepkg[8] and installed with linkman:pacman[8].
'repo-add' will update a package database by reading a built package file.
Multiple packages to add can be specified on the command line.
If a matching ``.sig'' file is found alongside a package file, the signature
will automatically be embedded into the database.
'repo-remove' will update a package database by removing the package name
specified on the command line. Multiple packages to remove can be specified
on the command line.
A package database is a tar file, optionally compressed. Valid extensions are
``.db'' followed by an archive extension of ``.tar'', ``.tar.bz2'',
``.tar.gz'', ``.tar.lrz'', ``.tar.lz'', ``.tar.lz4'', ``.tar.lzo'',
``.tar.xz'', ``.tar.zst'' or ``.tar.Z''. The file does not need to exist, but
all parent directories must exist.
Common Options
--------------
*-q, \--quiet*::
Force this program to keep quiet and run silently except for warning and
error messages.
*-s, \--sign*::
Generate a PGP signature file using GnuPG. This will execute `gpg
--detach-sign` on the generated database to generate a detached
signature file, using the GPG agent if it is available. The signature file
will be the entire filename of the database with a ``.sig'' extension.
*-k, \--key* <key>::
Specify a key to use when signing packages. Can also be specified using
the GPGKEY environment variable. If not specified in either location, the
default key from the keyring will be used.
*-v, \--verify*::
Verify the PGP signature of the database before updating the database.
If the signature is invalid, an error is produced and the update does not
proceed.
*\--nocolor*::
Remove color from 'repo-add' and 'repo-remove' output.
*-R, \--remove*::
Remove old package files from the disk when updating or removing their
entry in the database.
*-w, \--wait-for-lock*::
Wait for the lock file to be acquired. If unset, command will fail with
exit code 2 if acquiring the lock fails. If set, it will retry to acquire
lock until success.
repo-add Options
----------------
*-n, \--new*::
Only add packages that are not already in the database. Warnings will be
printed upon detection of existing packages, but they will not be re-added.
*\--include-sigs*::
Include package PGP signatures in the repository database (if available)
Example
-------
'repo-add' foo.db.tar.xz <pkg1> [<pkg2> ...]
This creates two separate databases; a smaller database ``foo.db.tar.xz'' used by
pacman and a large database containing package file lists ``foo.files.tar.xz'' for
use by other utilities. While pacman can use the large database (if renamed with a
db.tar* extension), there is currently no additional benefit for the larger download.
See Also
--------
linkman:makepkg[8], linkman:pacman[8]
include::footer.asciidoc[]

View file

@ -1,97 +0,0 @@
Pacman - Submitting Patches
===========================
This document is here mainly to make the job of those who review patches
easier and is more of a guideline and not a strict set of rules. However,
please try to follow as much as you can.
NOTE: Some of this is paraphrased from the kernel documentation's
"SubmittingPatches" file.
Getting the most recent source
------------------------------
Patches need to be submitted in Git format and are best if they are against the
latest version of the code. There are several helpful tutorials for getting
started with Git if you have not worked with it before.
* https://www.kernel.org/pub/software/scm/git/docs/gittutorial.html
* https://wiki.archlinux.org/index.php/Super_Quick_Git_Guide
The pacman code can be fetched using the following command:
git clone https://gitlab.archlinux.org/pacman/pacman.git
Before making large changes
---------------------------
--
* Discuss your idea
There is nothing worse that spending time making a change only for it to be
rejected immediately. Ensure ideas are discussed beforehand to avoid
disappointment. Appropriate locations for discussion are the issue tracker
on gitlab, or the pacman-dev mailing list. Transient discussion channels
such as IRC are not appropriate.
--
Creating your patch
-------------------
--
* Use `git commit -s` for creating a commit of your changes.
The -s allows you to credit yourself by adding a "Signed Off By" line to
indicate who has "signed" the patch - who has approved it.
Signed-off-by: Aaron Griffin <aaron@archlinux.org>
Please use your real name and email address. Feel free to "scramble" the
address if you're afraid of spam.
* Describe your patch.
It helps if you describe the overview and goals of the patch in the git commit
log. This allows others to see what you intended so as to compare it to what
was actually done, and allows better feedback.
--
Submitting your patch
---------------------
--
* Submit patches with a gitlab merge request
The pacman gitlab instance is the primary queue for review and acceptance.
Here you will get feedback, and let the reviewers know the details of your
patch.
--
After you submit
----------------
--
* Don't get discouraged
Any feedback you get, positive or negative, has nothing to do with you. If a
patch is rejected, try taking the suggestions into account and re-submitting.
We welcome most submissions here, and some may take a bit longer to get
looked over than others. If you think your patch got lost in the shuffle,
send another email to the list in reply to the original asking if anyone has
looked at it yet.
* Respond to feedback
When you do get feedback, it usually merits a response, whether this be a
resubmission of the patch with corrections or a follow-up email asking for
clarifications. When neither of these occurs, don't expect your patch to get
further review. The all-volunteer staff don't have time to fix up patches that
aren't their own.
--

View file

@ -1,20 +0,0 @@
testpkg(8)
==========
Name
----
testpkg - test a pacman package for validity
Synopsis
--------
'testpkg' <package file>
Description
-----------
'testpkg' is a script used to make sure that a pacman package is valid.
See Also
--------
linkman:pacman[8]
include::footer.asciidoc[]

View file

@ -1,159 +0,0 @@
Pacman - Translating
====================
This document is here to guide you in helping translate pacman messages,
libalpm messages, and the manual pages for the entire pacman package.
We are currently using https://app.transifex.com/[Transifex] as the translation
platform for pacman and libalpm. You will need to sign up for an account there
and then register with a translation team on the
https://explore.transifex.com/toofishes/archlinux-pacman/[pacman project page].
NOTE: This may be old information due to our switch to Transifex, but the
gettext website is a very useful guide to read before embarking on translation
work, as it describes many of the commands in more detail than I will here:
https://www.gnu.org/software/gettext/manual/html_node/gettext.html[].
Translating Messages
--------------------
Overview
~~~~~~~~
There are two separate message catalogs in pacman: one for the back-end
(libalpm) and one for the front-end (pacman and scripts). These correspond to
the `lib/libalpm/po` and `po` directories in the pacman source, respectively.
Translation message files are a specially formatted text file containing the
original message and the corresponding translation. These po files can then
either be hand-edited, or modified with a tool such as poedit, gtranslator or
kbabel. Using a translation tool tends to make the job easier.
Please read up on Transifex usage using the
https://help.transifex.com/[Transifex Help] if you are not familiar.
Transifex provides a command-line client to help with translations. Here is
an example set of commands if you have a source code checkout and are not
worried about any local translations being overwritten. The .tx/ directory is
checked into the git repository so is preconfigured with the two project
resources (See `tx status` output for a quick overview).
tx pull -f
poedit po/<mylang>.po
poedit lib/libalpm/po/<mylang>.po
tx push -t -l <mylang>
Or to just push one of the two available resources:
tx push -r archlinux-pacman.pacman-pot -t -l <mylang>
tx push -r archlinux-pacman.libalpm-pot -t -l <mylang>
See the <<Notes,Notes>> section for additional hints on translating.
Pre-release Updates
~~~~~~~~~~~~~~~~~~~
A week or two before each release, the codebase will go into a string freeze
and an email will be sent to the mailto:pacman-dev@lists.archlinux.org[pacman-dev]
mailing list asking for translations. An announcement in Transifex is also made,
which reaches everyone that is member of the translation team.
At this time, the latest `.po` language files will be made available at the
Transifex project page. Each language will have three files available (libalpm,
pacman and pacman-scripts). Translators interested in helping are encouraged to use the
features of Transifex to let others know they are currently translating their
language.
Once a translator has completed the translation offline (*OR* realizes they do not have
time to finish), please upload your progress back to the Transifex site.
NOTE: Please upload your translations as soon as possible - this will give other
speakers of your language time to review your translations and update them as
necessary.
Incremental Updates
~~~~~~~~~~~~~~~~~~~
If you have more advanced needs you will have to get a copy of the pacman
repository.
git clone https://gitlab.archlinux.org/pacman/pacman.git
Next, you will need to configure the build environment. From the base directory,
run:
meson setup . build
If any required dependencies are missing, please install. After that,
update the template translation (.pot) files to the latest state of
the source code by running:
meson compile -C build pacman-scripts-pot pacman-pot libalpm-pot
We need to first update the main message catalog file. Navigate into either
the `lib/libalpm/po`, `scripts/po` or `src/pacman/po` directory depending
on which translation you wish to work on first, and execute the following
command to update your specific language's translation file
(replace `lang_code` with your language code e.g. 'pt_BR', and `pot_file`
with `libalpm.pot`, `pacman.pot` or `pacman-scripts.pot`):
msgmerge --update --previous <lang_code>.po <pot_filename>.pot
At this point, you can do the translation. To submit your changes, either email
the new `.po` file to the mailing-list with *[translation]* in the subject, or
submit a Git-formatted patch (please do not include any `.pot` file changes).
As a shortcut, all translation files (including `.pot` files) can be updated
with the following command:
./build-aux/update-po
Adding a New Language
~~~~~~~~~~~~~~~~~~~~~
Making a new language is not too hard, but be sure to follow all the steps.
You will have to do the following steps in both the `lib/libalpm/po/` and `po/`
directories, substituting where appropriate. First, edit the `LINGUAS` file and
add your new language code at the bottom. Next, run the following command,
substituting `libalpm.pot` or `pacman.pot` for potfile depending on which
directory you are currently working in:
msginit -l <lang_code> -o <lang_code>.po -i <potfile>
You can then also add your language code to the end of the `LINGUAS` file
located in each po directory.
Look at the current message files for more guidance if necessary. Once you
create the new language file, you may need to slightly modify the headers;
try to make them look similar to the other .po file headers. In addition, for
all new translations we would strongly recommend using UTF-8 encoding.
Notes[[Notes]]
~~~~~~~~~~~~~~
msgid and msgstr 'variables' can be on as many lines as necessary. Line breaks
are ignored; if you need a literal line break, use an `\n` in your string. The
following two translations are equivalent:
msgstr "This is a test translation"
msgstr ""
"This is a test translation"
If you want to test the translation (copy the .po file you want to test,
you may ignore the rest), replacing `<lang_code>` accordingly:
meson compile -C build pacman-scripts-gmo pacman-gmo libalpm-gmo
cp ./build/lib/libalpm/po/<lang_code>/LC_MESSAGES/libalpm.mo /usr/share/locale/<lang_code>/LC_MESSAGES/libalpm.mo
cp ./build/scripts/po/<lang_code>/LC_MESSAGES/pacman-scripts.mo /usr/share/locale/<lang_code>/LC_MESSAGES/pacman-scripts.mo
cp ./build/src/pacman/po/<lang_code>/LC_MESSAGES/pacman.mo /usr/share/locale/<lang_code>/LC_MESSAGES/pacman.mo
Translating Manpages
--------------------
There are currently no efforts underway to include translated manual pages in
the pacman codebase. However, this is not to say translations are unwelcome. If
someone has experience with i18n man pages and how to best include them with our
source, please contact the pacman-dev mailing list at
mailto:pacman-dev@lists.archlinux.org[].

View file

@ -1,72 +0,0 @@
vercmp(8)
=========
Name
----
vercmp - version comparison utility
Synopsis
--------
'vercmp' [-h] [--help] <version1> <version2>
Description
-----------
'vercmp' is used to determine the relationship between two given version
numbers. It outputs values as follows:
* < 0 : if ver1 < ver2
* = 0 : if ver1 == ver2
* > 0 : if ver1 > ver2
Version comparison operates as follows:
Alphanumeric:
1.0a < 1.0b < 1.0beta < 1.0p < 1.0pre < 1.0rc < 1.0 < 1.0.a < 1.0.1
Numeric:
1 < 1.0 < 1.1 < 1.1.1 < 1.2 < 2.0 < 3.0.0
Additionally, version strings can have an 'epoch' value defined that will
overrule any version comparison, unless the epoch values are equal. This is
specified in an `epoch:version-rel` format. For example, `2:1.0-1` is always
greater than `1:3.6-1`.
Keep in mind that the 'pkgrel' is only compared if it is available on both
versions given to this tool. For example, comparing `1.5-1` and `1.5` will
yield 0; comparing `1.5-1` and `1.5-2` will yield < 0 as expected. This is
mainly for supporting versioned dependencies that do not include the 'pkgrel'.
Options
-------
*-h, \--help*::
Display summary of the available return codes. Must be the first option
specified.
Examples
--------
$ vercmp 1 2
-1
$ vercmp 2 1
1
$ vercmp 2.0-1 1.7-6
1
$ vercmp 2.0 2.0-13
0
$ vercmp 4.34 1:001
-1
See Also
--------
linkman:pacman[8], linkman:makepkg[8], linkman:libalpm[3]
include::footer.asciidoc[]

2
etc/.gitignore vendored
View file

@ -1,2 +0,0 @@
makepkg.conf
pacman.conf

59
etc/makepkg.conf Normal file
View file

@ -0,0 +1,59 @@
#
# /etc/makepkg.conf
#
#########################################################################
# SOURCE ACQUISITION
#########################################################################
#
#-- The FTP/HTTP download utility that makepkg should use to acquire sources
export FTPAGENT="/usr/bin/wget --continue --passive-ftp --tries=3 --waitretry=3 --no-check-certificate"
#export FTPAGENT="/usr/bin/snarf"
#export FTPAGENT="/usr/bin/lftpget -c"
#########################################################################
# ARCHITECTURE, COMPILE FLAGS
#########################################################################
#
export CARCH="i686"
export CHOST="i686-pc-linux-gnu"
#-- Exclusive: will only run on i686 or higher (P6, Athlon)
export CFLAGS="-march=i686 -O2 -pipe"
export CXXFLAGS="-march=i686 -O2 -pipe"
#-- Optimized: will run on any x86, but optimized for i686
#export CFLAGS="-mcpu=i686 -O2 -pipe"
#export CXXFLAGS="-mcpu=i686 -O2 -pipe"
#-- Make Flags: change this for DistCC/SMP systems
#export MAKEFLAGS="-j2"
#########################################################################
# BUILD ENVIRONMENT
#########################################################################
#
#-- Fakeroot: for building packages as a non-root user
export USE_FAKEROOT="y"
#-- DistCC: a distributed C/C++/ObjC compiler (modify MAKEFLAGS too)
export DISTCC="n"
#-- A space-delimited list of hosts running in the DistCC cluster
export DISTCC_HOSTS=""
#-- Colorized output messages
export USE_COLOR="y"
#########################################################################
# GLOBAL PACKAGE OPTIONS
#########################################################################
#
#-- Don't strip symbols from binaries/libraries
#export NOSTRIP="1"
#-- Keep doc and info directories
#export KEEPDOCS="1"
#########################################################################
# PACKAGE OUTPUT
#########################################################################
#
#-- Destination: specify a fixed directory where all packages will be placed
#export PKGDEST=/home/packages
#-- Packager: name/email of the person or organization building packages
#export PACKAGER="John Doe <john@doe.com>"

View file

@ -1,18 +0,0 @@
#!/hint/bash
#
# @sysconfdir@/makepkg.conf.d/fortran.conf
#
#########################################################################
# FORTRAN LANGUAGE SUPPORT
#########################################################################
# Flags used for the Fortran compiler, similar in spirit to CFLAGS. Read
# linkman:gfortran[1] for more details on the available flags.
#FFLAGS="-O2 -pipe"
#FCFLAGS="$FFLAGS"
# Additional compiler flags appended to `FFLAGS` and `FCFLAGS` for use in debugging. Usually
# this would include: ``-g''. Read linkman:gfortran[1] for more details on the wide
# variety of compiler flags available.
#DEBUG_FFLAGS="-g"

View file

@ -1,17 +0,0 @@
#!/hint/bash
#
# @sysconfdir@/makepkg.conf.d/rust.conf
#
#########################################################################
# RUST LANGUAGE SUPPORT
#########################################################################
# Flags used for the Rust compiler, similar in spirit to CFLAGS. Read
# linkman:rustc[1] for more details on the available flags.
#RUSTFLAGS="-C opt-level=3"
# Additional compiler flags appended to `RUSTFLAGS` for use in debugging.
# Usually this would include: ``-C debuginfo=2''. Read linkman:rustc[1] for
# more details on the available flags.
#DEBUG_RUSTFLAGS="-C debuginfo=2"

View file

@ -1,161 +0,0 @@
#!/hint/bash
#
# @sysconfdir@/makepkg.conf
#
#########################################################################
# SOURCE ACQUISITION
#########################################################################
#
#-- The download utilities that makepkg should use to acquire sources
# Format: 'protocol::agent'
DLAGENTS=('file::/usr/bin/curl -qgC - -o %o %u'
'ftp::/usr/bin/curl -qgfC - --ftp-pasv --retry 3 --retry-delay 3 -o %o %u'
'http::/usr/bin/curl -qgb "" -fLC - --retry 3 --retry-delay 3 -o %o %u'
'https::/usr/bin/curl -qgb "" -fLC - --retry 3 --retry-delay 3 -o %o %u'
'rsync::/usr/bin/rsync --no-motd -z %u %o'
'scp::/usr/bin/scp -C %u %o')
# Other common tools:
# /usr/bin/snarf
# /usr/bin/lftpget -c
# /usr/bin/wget
#-- The package required by makepkg to download VCS sources
# Format: 'protocol::package'
VCSCLIENTS=('bzr::breezy'
'fossil::fossil'
'git::git'
'hg::mercurial'
'svn::subversion')
#########################################################################
# ARCHITECTURE, COMPILE FLAGS
#########################################################################
#
CARCH="@CARCH@"
CHOST="@CHOST@"
#NPROC=2
#-- Compiler and Linker Flags
#CPPFLAGS=""
#CFLAGS="-O2 -pipe"
#CXXFLAGS="-O2 -pipe"
#LDFLAGS=""
#LTOFLAGS="-flto"
#-- Make Flags: change this for DistCC/SMP systems
#MAKEFLAGS="-j2"
#-- Debugging flags
#DEBUG_CFLAGS="-g"
#DEBUG_CXXFLAGS="-g"
#########################################################################
# BUILD ENVIRONMENT
#########################################################################
#
# Makepkg defaults: BUILDENV=(!distcc !color !ccache check !sign)
# A negated environment option will do the opposite of the comments below.
#
#-- distcc: Use the Distributed C/C++/ObjC compiler
#-- color: Colorize output messages
#-- ccache: Use ccache to cache compilation
#-- check: Run the check() function if present in the PKGBUILD
#-- sign: Generate PGP signature file
#
BUILDENV=(!distcc color !ccache check !sign)
#
#-- If using DistCC, your MAKEFLAGS will also need modification. In addition,
#-- specify a space-delimited list of hosts running in the DistCC cluster.
#DISTCC_HOSTS=""
#
#-- Specify a directory for package building.
#BUILDDIR=/tmp/makepkg
#########################################################################
# GLOBAL PACKAGE OPTIONS
# These are default values for the options=() settings
#########################################################################
#
# Makepkg defaults:
# OPTIONS=(!strip docs libtool staticlibs emptydirs !zipman !purge !debug !lto !autodeps)
# A negated option will do the opposite of the comments below.
#
#-- strip: Strip symbols from binaries/libraries
#-- docs: Save doc directories specified by DOC_DIRS
#-- libtool: Leave libtool (.la) files in packages
#-- staticlibs: Leave static library (.a) files in packages
#-- emptydirs: Leave empty directories in packages
#-- zipman: Compress manual (man and info) pages in MAN_DIRS with gzip
#-- purge: Remove files specified by PURGE_TARGETS
#-- debug: Add debugging flags as specified in DEBUG_* variables
#-- lto: Add compile flags for building with link time optimization
#-- autodeps: Automatically add depends/provides
#
OPTIONS=(strip docs libtool staticlibs emptydirs zipman purge !debug !lto !autodeps)
#-- File integrity checks to use. Valid: ck, md5, sha1, sha224, sha256, sha384, sha512, b2
INTEGRITY_CHECK=(ck)
#-- Options to be used when stripping binaries. See `man strip' for details.
STRIP_BINARIES="@STRIP_BINARIES@"
#-- Options to be used when stripping shared libraries. See `man strip' for details.
STRIP_SHARED="@STRIP_SHARED@"
#-- Options to be used when stripping static libraries. See `man strip' for details.
STRIP_STATIC="@STRIP_STATIC@"
#-- Manual (man and info) directories to compress (if zipman is specified)
MAN_DIRS=({usr{,/local}{,/share},opt/*}/{man,info})
#-- Doc directories to remove (if !docs is specified)
DOC_DIRS=(usr/{,local/}{,share/}{doc,gtk-doc} opt/*/{doc,gtk-doc})
#-- Files to be removed from all packages (if purge is specified)
PURGE_TARGETS=(usr/{,share}/info/dir .packlist *.pod)
#-- Directory to store source code in for debug packages
DBGSRCDIR="/usr/src/debug"
#-- Prefix and directories for library autodeps
LIB_DIRS=('lib:usr/lib' 'lib32:usr/lib32')
#########################################################################
# PACKAGE OUTPUT
#########################################################################
#
# Default: put built package and cached source in build directory
#
#-- Destination: specify a fixed directory where all packages will be placed
#PKGDEST=/home/packages
#-- Source cache: specify a fixed directory where source files will be cached
#SRCDEST=/home/sources
#-- Source packages: specify a fixed directory where all src packages will be placed
#SRCPKGDEST=/home/srcpackages
#-- Log files: specify a fixed directory where all log files will be placed
#LOGDEST=/home/makepkglogs
#-- Packager: name/email of the person or organization building packages
#PACKAGER="John Doe <john@doe.com>"
#-- Specify a key to use for package signing
#GPGKEY=""
#########################################################################
# COMPRESSION DEFAULTS
#########################################################################
#
COMPRESSGZ=(gzip -c -f -n)
COMPRESSBZ2=(bzip2 -c -f)
COMPRESSXZ=(xz -c -z -)
COMPRESSZST=(zstd -c -z -q -)
COMPRESSLRZ=(lrzip -q)
COMPRESSLZO=(lzop -q)
COMPRESSZ=(compress -c -f)
COMPRESSLZ4=(lz4 -q)
COMPRESSLZ=(lzip -c -f)
#########################################################################
# EXTENSION DEFAULTS
#########################################################################
#
PKGEXT='@PKGEXT@'
SRCEXT='@SRCEXT@'
#########################################################################
# OTHER
#########################################################################
#
#-- Command used to run pacman as root, instead of trying sudo and su
PACMAN_AUTH=()

53
etc/pacman.conf Normal file
View file

@ -0,0 +1,53 @@
#
# /etc/pacman.conf
#
# NOTE: If you find a mirror that is geographically close to you, please
# move it to the top of the server list, so pacman will choose it
# first.
#
# To re-sort your mirror lists by ping/traceroute results, use the
# /usr/bin/sortmirrors.pl script. It requires the "netselect" package.
#
# # sortmirrors.pl </etc/pacman.conf >pacman.conf.new
#
# See the pacman manpage for option directives
#
# GENERAL OPTIONS
#
[options]
LogFile = /var/log/pacman.log
NoUpgrade = etc/passwd etc/group etc/shadow etc/sudoers
NoUpgrade = etc/fstab etc/raidtab etc/mdadm.conf etc/ld.so.conf
NoUpgrade = etc/inittab etc/rc.conf etc/rc.local
NoUpgrade = etc/modprobe.conf etc/modules.conf
NoUpgrade = etc/lilo.conf boot/grub/menu.lst etc/mkinitrd.conf
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

View file

@ -1,79 +0,0 @@
#
# @sysconfdir@/pacman.conf
#
# See the pacman.conf(5) manpage for option and repository directives
#
# GENERAL OPTIONS
#
[options]
# The following paths are commented out with their default values listed.
# If you wish to use different paths, uncomment and update the paths.
#RootDir = @ROOTDIR@
#DBPath = @localstatedir@/lib/pacman/
#CacheDir = @localstatedir@/cache/pacman/pkg/
#LogFile = @localstatedir@/log/pacman.log
#GPGDir = @sysconfdir@/pacman.d/gnupg/
#HookDir = @sysconfdir@/pacman.d/hooks/
HoldPkg = pacman glibc
#XferCommand = /usr/bin/curl -L -C - -f -o %o %u
#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u
#CleanMethod = KeepInstalled
Architecture = auto
# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup
#IgnorePkg =
#IgnoreGroup =
#NoUpgrade =
#NoExtract =
# Misc options
#UseSyslog
#Color
#NoProgressBar
CheckSpace
#VerbosePkgLists
ParallelDownloads = 5
#DownloadUser = alpm
#DisableSandbox
# PGP signature checking
#SigLevel = Optional
#LocalFileSigLevel = Optional
#RemoteFileSigLevel = Optional
#
# 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
# - repositories listed first will take precedence when packages
# have identical names, regardless of version number
# - URLs will have $repo replaced by the name of the current repo
# - URLs will have $arch replaced by the name of the architecture
#
# Repository entries are of the format:
# [repo-name]
# Server = ServerName
# Include = IncludePath
#
# The header [repo-name] is crucial - it must be present and
# uncommented to enable the repo.
#
# An example of a disabled remote package repository with multiple servers
# available. To enable, uncomment the following lines. You can add preferred
# servers immediately after the header and they will be used before the
# default mirrors.
#[core]
#SigLevel = Required
#Server = ftp://ftp.example.com/foobar/$repo/os/$arch/
# The file referenced here should contain a list of 'Server = ' lines.
#Include = @sysconfdir@/pacman.d/mirrorlist
# An example of a custom package repository. See the pacman manpage for
# tips on creating your own repositories.
#[custom]
#SigLevel = Optional TrustAll
#Server = file:///home/packages

251
install-sh Executable file
View file

@ -0,0 +1,251 @@
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
#
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
:
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
chmodcmd=""
else
instcmd=$mkdirprog
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
:
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
:
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
:
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
:
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
:
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0

View file

@ -1,5 +0,0 @@
.deps
.libs
*.lo
*.la
libalpm.pc

View file

@ -1,695 +0,0 @@
/*
* add.c
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdint.h> /* int64_t */
/* libarchive */
#include <archive.h>
#include <archive_entry.h>
/* libalpm */
#include "add.h"
#include "alpm.h"
#include "alpm_list.h"
#include "handle.h"
#include "libarchive-compat.h"
#include "trans.h"
#include "util.h"
#include "log.h"
#include "backup.h"
#include "package.h"
#include "db.h"
#include "remove.h"
#include "handle.h"
int SYMEXPORT alpm_add_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg)
{
const char *pkgname, *pkgver;
alpm_trans_t *trans;
alpm_pkg_t *local;
alpm_pkg_t *dup;
/* Sanity checks */
CHECK_HANDLE(handle, return -1);
ASSERT(pkg != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
ASSERT(pkg->origin != ALPM_PKG_FROM_LOCALDB,
RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
ASSERT(handle == pkg->handle, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
trans = handle->trans;
ASSERT(trans != NULL, RET_ERR(handle, ALPM_ERR_TRANS_NULL, -1));
ASSERT(trans->state == STATE_INITIALIZED,
RET_ERR(handle, ALPM_ERR_TRANS_NOT_INITIALIZED, -1));
pkgname = pkg->name;
pkgver = pkg->version;
_alpm_log(handle, ALPM_LOG_DEBUG, "adding package '%s'\n", pkgname);
if((dup = alpm_pkg_find(trans->add, pkgname))) {
if(dup == pkg) {
_alpm_log(handle, ALPM_LOG_DEBUG, "skipping duplicate target: %s\n", pkgname);
return 0;
}
/* error for separate packages with the same name */
RET_ERR(handle, ALPM_ERR_TRANS_DUP_TARGET, -1);
}
if((local = _alpm_db_get_pkgfromcache(handle->db_local, pkgname))) {
const char *localpkgname = local->name;
const char *localpkgver = local->version;
int cmp = _alpm_pkg_compare_versions(pkg, local);
if(cmp == 0) {
if(trans->flags & ALPM_TRANS_FLAG_NEEDED) {
/* with the NEEDED flag, packages up to date are not reinstalled */
_alpm_log(handle, ALPM_LOG_WARNING, _("%s-%s is up to date -- skipping\n"),
localpkgname, localpkgver);
return 0;
} else if(!(trans->flags & ALPM_TRANS_FLAG_DOWNLOADONLY)) {
_alpm_log(handle, ALPM_LOG_WARNING, _("%s-%s is up to date -- reinstalling\n"),
localpkgname, localpkgver);
}
} else if(cmp < 0 && !(trans->flags & ALPM_TRANS_FLAG_DOWNLOADONLY)) {
/* local version is newer */
_alpm_log(handle, ALPM_LOG_WARNING, _("downgrading package %s (%s => %s)\n"),
localpkgname, localpkgver, pkgver);
}
}
/* add the package to the transaction */
pkg->reason = ALPM_PKG_REASON_EXPLICIT;
_alpm_log(handle, ALPM_LOG_DEBUG, "adding package %s-%s to the transaction add list\n",
pkgname, pkgver);
trans->add = alpm_list_add(trans->add, pkg);
return 0;
}
static int perform_extraction(alpm_handle_t *handle, struct archive *archive,
struct archive_entry *entry, const char *filename)
{
int ret;
struct archive *archive_writer;
const int archive_flags = ARCHIVE_EXTRACT_OWNER |
ARCHIVE_EXTRACT_PERM |
ARCHIVE_EXTRACT_TIME |
ARCHIVE_EXTRACT_UNLINK |
ARCHIVE_EXTRACT_XATTR |
ARCHIVE_EXTRACT_SECURE_SYMLINKS;
archive_entry_set_pathname(entry, filename);
archive_writer = archive_write_disk_new();
if (archive_writer == NULL) {
_alpm_log(handle, ALPM_LOG_ERROR, _("cannot allocate disk archive object"));
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"error: cannot allocate disk archive object");
return 1;
}
archive_write_disk_set_options(archive_writer, archive_flags);
ret = archive_read_extract2(archive, entry, archive_writer);
archive_write_free(archive_writer);
if(ret == ARCHIVE_WARN && archive_errno(archive) != ENOSPC) {
/* operation succeeded but a "non-critical" error was encountered */
_alpm_log(handle, ALPM_LOG_WARNING, _("warning given when extracting %s (%s)\n"),
filename, archive_error_string(archive));
} else if(ret != ARCHIVE_OK) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not extract %s (%s)\n"),
filename, archive_error_string(archive));
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"error: could not extract %s (%s)\n",
filename, archive_error_string(archive));
return 1;
}
return 0;
}
static int try_rename(alpm_handle_t *handle, const char *src, const char *dest)
{
if(rename(src, dest)) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
src, dest, strerror(errno));
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"error: could not rename %s to %s (%s)\n", src, dest, strerror(errno));
return 1;
}
return 0;
}
static int extract_db_file(alpm_handle_t *handle, struct archive *archive,
struct archive_entry *entry, alpm_pkg_t *newpkg, const char *entryname)
{
char filename[PATH_MAX]; /* the actual file we're extracting */
const char *dbfile = NULL;
if(strcmp(entryname, ".INSTALL") == 0) {
dbfile = "install";
} else if(strcmp(entryname, ".CHANGELOG") == 0) {
dbfile = "changelog";
} else if(strcmp(entryname, ".MTREE") == 0) {
dbfile = "mtree";
} else if(*entryname == '.') {
/* reserve all files starting with '.' for future possibilities */
_alpm_log(handle, ALPM_LOG_DEBUG, "skipping extraction of '%s'\n", entryname);
archive_read_data_skip(archive);
return 0;
}
archive_entry_set_perm(entry, 0644);
snprintf(filename, PATH_MAX, "%s%s-%s/%s",
_alpm_db_path(handle->db_local), newpkg->name, newpkg->version, dbfile);
return perform_extraction(handle, archive, entry, filename);
}
static int extract_single_file(alpm_handle_t *handle, struct archive *archive,
struct archive_entry *entry, alpm_pkg_t *newpkg, alpm_pkg_t *oldpkg)
{
const char *entryname = archive_entry_pathname(entry);
mode_t entrymode = archive_entry_mode(entry);
alpm_backup_t *backup = _alpm_needbackup(entryname, newpkg);
char filename[PATH_MAX]; /* the actual file we're extracting */
int needbackup = 0, notouch = 0;
const char *hash_orig = NULL;
int isnewfile = 0, errors = 0;
struct stat lsbuf;
size_t filename_len;
if(*entryname == '.') {
return extract_db_file(handle, archive, entry, newpkg, entryname);
}
if (!alpm_filelist_contains(&newpkg->files, entryname)) {
_alpm_log(handle, ALPM_LOG_WARNING,
_("file not found in file list for package %s. skipping extraction of %s\n"),
newpkg->name, entryname);
return 0;
}
/* build the new entryname relative to handle->root */
filename_len = snprintf(filename, PATH_MAX, "%s%s", handle->root, entryname);
if(filename_len >= PATH_MAX) {
_alpm_log(handle, ALPM_LOG_ERROR,
_("unable to extract %s%s: path too long"), handle->root, entryname);
return 1;
}
/* if a file is in NoExtract then we never extract it */
if(_alpm_fnmatch_patterns(handle->noextract, entryname) == 0) {
_alpm_log(handle, ALPM_LOG_DEBUG, "%s is in NoExtract,"
" skipping extraction of %s\n",
entryname, filename);
archive_read_data_skip(archive);
return 0;
}
/* Check for file existence. This is one of the more crucial parts
* to get 'right'. Here are the possibilities, with the filesystem
* on the left and the package on the top:
* (F=file, N=node, S=symlink, D=dir)
* | F/N | D
* non-existent | 1 | 2
* F/N | 3 | 4
* D | 5 | 6
*
* 1,2- extract, no magic necessary. lstat (llstat) will fail here.
* 3,4- conflict checks should have caught this. either overwrite
* or backup the file.
* 5- file replacing directory- don't allow it.
* 6- skip extraction, dir already exists.
*/
isnewfile = llstat(filename, &lsbuf) != 0;
if(isnewfile) {
/* cases 1,2: file doesn't exist, skip all backup checks */
} else if(S_ISDIR(lsbuf.st_mode) && S_ISDIR(entrymode)) {
#if 0
uid_t entryuid = archive_entry_uid(entry);
gid_t entrygid = archive_entry_gid(entry);
#endif
/* case 6: existing dir, ignore it */
if(lsbuf.st_mode != entrymode) {
/* if filesystem perms are different than pkg perms, warn user */
mode_t mask = 07777;
_alpm_log(handle, ALPM_LOG_WARNING, _("directory permissions differ on %s\n"
"filesystem: %o package: %o\n"), filename, lsbuf.st_mode & mask,
entrymode & mask);
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"warning: directory permissions differ on %s, "
"filesystem: %o package: %o\n", filename, lsbuf.st_mode & mask,
entrymode & mask);
}
#if 0
/* Disable this warning until our user management in packages has improved.
Currently many packages have to create users in post_install and chown the
directories. These all resulted in "false-positive" warnings. */
if((entryuid != lsbuf.st_uid) || (entrygid != lsbuf.st_gid)) {
_alpm_log(handle, ALPM_LOG_WARNING, _("directory ownership differs on %s\n"
"filesystem: %u:%u package: %u:%u\n"), filename,
lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid);
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"warning: directory ownership differs on %s, "
"filesystem: %u:%u package: %u:%u\n", filename,
lsbuf.st_uid, lsbuf.st_gid, entryuid, entrygid);
}
#endif
_alpm_log(handle, ALPM_LOG_DEBUG, "extract: skipping dir extraction of %s\n",
filename);
archive_read_data_skip(archive);
return 0;
} else if(S_ISDIR(lsbuf.st_mode)) {
/* case 5: trying to overwrite dir with file, don't allow it */
_alpm_log(handle, ALPM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"),
filename);
archive_read_data_skip(archive);
return 1;
} else if(S_ISDIR(entrymode)) {
/* case 4: trying to overwrite file with dir */
_alpm_log(handle, ALPM_LOG_DEBUG, "extract: overwriting file with dir %s\n",
filename);
} else {
/* case 3: trying to overwrite file with file */
/* if file is in NoUpgrade, don't touch it */
if(_alpm_fnmatch_patterns(handle->noupgrade, entryname) == 0) {
notouch = 1;
} else {
alpm_backup_t *oldbackup;
if(oldpkg && (oldbackup = _alpm_needbackup(entryname, oldpkg))) {
hash_orig = oldbackup->hash;
needbackup = 1;
} else if(backup) {
/* allow adding backup files retroactively */
needbackup = 1;
}
}
}
if(notouch || needbackup) {
if(filename_len + strlen(".pacnew") >= PATH_MAX) {
_alpm_log(handle, ALPM_LOG_ERROR,
_("unable to extract %s.pacnew: path too long"), filename);
return 1;
}
strcpy(filename + filename_len, ".pacnew");
isnewfile = (llstat(filename, &lsbuf) != 0 && errno == ENOENT);
}
_alpm_log(handle, ALPM_LOG_DEBUG, "extracting %s\n", filename);
if(perform_extraction(handle, archive, entry, filename)) {
errors++;
return errors;
}
if(backup) {
FREE(backup->hash);
backup->hash = alpm_compute_md5sum(filename);
}
if(notouch) {
alpm_event_pacnew_created_t event = {
.type = ALPM_EVENT_PACNEW_CREATED,
.from_noupgrade = 1,
.oldpkg = oldpkg,
.newpkg = newpkg,
.file = filename
};
/* "remove" the .pacnew suffix */
filename[filename_len] = '\0';
EVENT(handle, &event);
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"warning: %s installed as %s.pacnew\n", filename, filename);
} else if(needbackup) {
char *hash_local = NULL, *hash_pkg = NULL;
char origfile[PATH_MAX] = "";
strncat(origfile, filename, filename_len);
hash_local = alpm_compute_md5sum(origfile);
hash_pkg = backup ? backup->hash : alpm_compute_md5sum(filename);
_alpm_log(handle, ALPM_LOG_DEBUG, "checking hashes for %s\n", origfile);
_alpm_log(handle, ALPM_LOG_DEBUG, "current: %s\n", hash_local);
_alpm_log(handle, ALPM_LOG_DEBUG, "new: %s\n", hash_pkg);
_alpm_log(handle, ALPM_LOG_DEBUG, "original: %s\n", hash_orig);
if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) {
/* local and new files are the same, updating anyway to get
* correct timestamps */
_alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
origfile);
if(try_rename(handle, filename, origfile)) {
errors++;
}
} else if(hash_orig && hash_pkg && strcmp(hash_orig, hash_pkg) == 0) {
/* original and new files are the same, leave the local version alone,
* including any user changes */
_alpm_log(handle, ALPM_LOG_DEBUG,
"action: leaving existing file in place\n");
if(isnewfile) {
unlink(filename);
}
} else if(hash_orig && hash_local && strcmp(hash_orig, hash_local) == 0) {
/* installed file has NOT been changed by user,
* update to the new version */
_alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n",
origfile);
if(try_rename(handle, filename, origfile)) {
errors++;
}
} else {
/* none of the three files matched another, leave the unpacked
* file alongside the local file */
alpm_event_pacnew_created_t event = {
.type = ALPM_EVENT_PACNEW_CREATED,
.from_noupgrade = 0,
.oldpkg = oldpkg,
.newpkg = newpkg,
.file = origfile
};
_alpm_log(handle, ALPM_LOG_DEBUG,
"action: keeping current file and installing"
" new one with .pacnew ending\n");
EVENT(handle, &event);
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"warning: %s installed as %s\n", origfile, filename);
}
free(hash_local);
if(!backup) {
free(hash_pkg);
}
}
return errors;
}
static int commit_single_pkg(alpm_handle_t *handle, alpm_pkg_t *newpkg,
size_t pkg_current, size_t pkg_count)
{
int ret = 0, errors = 0;
int is_upgrade = 0;
alpm_pkg_t *oldpkg = NULL;
alpm_db_t *db = handle->db_local;
alpm_trans_t *trans = handle->trans;
alpm_progress_t progress = ALPM_PROGRESS_ADD_START;
alpm_event_package_operation_t event;
const char *log_msg = "adding";
const char *pkgfile;
struct archive *archive;
struct archive_entry *entry;
int fd, cwdfd;
struct stat buf;
ASSERT(trans != NULL, return -1);
/* see if this is an upgrade. if so, remove the old package first */
if(_alpm_db_get_pkgfromcache(db, newpkg->name) && (oldpkg = newpkg->oldpkg)) {
int cmp = _alpm_pkg_compare_versions(newpkg, oldpkg);
if(cmp < 0) {
log_msg = "downgrading";
progress = ALPM_PROGRESS_DOWNGRADE_START;
event.operation = ALPM_PACKAGE_DOWNGRADE;
} else if(cmp == 0) {
log_msg = "reinstalling";
progress = ALPM_PROGRESS_REINSTALL_START;
event.operation = ALPM_PACKAGE_REINSTALL;
} else {
log_msg = "upgrading";
progress = ALPM_PROGRESS_UPGRADE_START;
event.operation = ALPM_PACKAGE_UPGRADE;
}
is_upgrade = 1;
/* copy over the install reason */
newpkg->reason = alpm_pkg_get_reason(oldpkg);
} else {
event.operation = ALPM_PACKAGE_INSTALL;
}
event.type = ALPM_EVENT_PACKAGE_OPERATION_START;
event.oldpkg = oldpkg;
event.newpkg = newpkg;
EVENT(handle, &event);
pkgfile = newpkg->origin_data.file;
_alpm_log(handle, ALPM_LOG_DEBUG, "%s package %s-%s\n",
log_msg, newpkg->name, newpkg->version);
/* pre_install/pre_upgrade scriptlet */
if(alpm_pkg_has_scriptlet(newpkg) &&
!(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) {
const char *scriptlet_name = is_upgrade ? "pre_upgrade" : "pre_install";
_alpm_runscriptlet(handle, pkgfile, scriptlet_name,
newpkg->version, oldpkg ? oldpkg->version : NULL, 1);
}
/* we override any pre-set reason if we have alldeps or allexplicit set */
if(trans->flags & ALPM_TRANS_FLAG_ALLDEPS) {
newpkg->reason = ALPM_PKG_REASON_DEPEND;
} else if(trans->flags & ALPM_TRANS_FLAG_ALLEXPLICIT) {
newpkg->reason = ALPM_PKG_REASON_EXPLICIT;
}
if(oldpkg) {
/* set up fake remove transaction */
if(_alpm_remove_single_package(handle, oldpkg, newpkg, 0, 0) == -1) {
handle->pm_errno = ALPM_ERR_TRANS_ABORT;
return -1;
}
}
/* prepare directory for database entries so permissions are correct after
changelog/install script installation */
if(_alpm_local_db_prepare(db, newpkg)) {
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"error: could not create database entry %s-%s\n",
newpkg->name, newpkg->version);
handle->pm_errno = ALPM_ERR_DB_WRITE;
return -1;
}
fd = _alpm_open_archive(db->handle, pkgfile, &buf,
&archive, ALPM_ERR_PKG_OPEN);
if(fd < 0) {
return -1;
}
/* save the cwd so we can restore it later */
OPEN(cwdfd, ".", O_RDONLY | O_CLOEXEC);
if(cwdfd < 0) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n"));
}
/* libarchive requires this for extracting hard links */
if(chdir(handle->root) != 0) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"),
handle->root, strerror(errno));
_alpm_archive_read_free(archive);
if(cwdfd >= 0) {
close(cwdfd);
}
close(fd);
return -1;
}
if(trans->flags & ALPM_TRANS_FLAG_DBONLY) {
_alpm_log(handle, ALPM_LOG_DEBUG, "extracting db files\n");
while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
const char *entryname = archive_entry_pathname(entry);
if(entryname[0] == '.') {
errors += extract_db_file(handle, archive, entry, newpkg, entryname);
} else {
archive_read_data_skip(archive);
}
}
} else {
_alpm_log(handle, ALPM_LOG_DEBUG, "extracting files\n");
/* call PROGRESS once with 0 percent, as we sort-of skip that here */
PROGRESS(handle, progress, newpkg->name, 0, pkg_count, pkg_current);
while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
int percent;
if(newpkg->size != 0) {
/* Using compressed size for calculations here, as newpkg->isize is not
* exact when it comes to comparing to the ACTUAL uncompressed size
* (missing metadata sizes) */
int64_t pos = _alpm_archive_compressed_ftell(archive);
percent = (pos * 100) / newpkg->size;
if(percent >= 100) {
percent = 100;
}
} else {
percent = 0;
}
PROGRESS(handle, progress, newpkg->name, percent, pkg_count, pkg_current);
/* extract the next file from the archive */
errors += extract_single_file(handle, archive, entry, newpkg, oldpkg);
}
}
_alpm_archive_read_free(archive);
close(fd);
/* restore the old cwd if we have it */
if(cwdfd >= 0) {
if(fchdir(cwdfd) != 0) {
_alpm_log(handle, ALPM_LOG_ERROR,
_("could not restore working directory (%s)\n"), strerror(errno));
}
close(cwdfd);
}
if(errors) {
ret = -1;
if(is_upgrade) {
_alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while upgrading %s\n"),
newpkg->name);
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"error: problem occurred while upgrading %s\n",
newpkg->name);
} else {
_alpm_log(handle, ALPM_LOG_ERROR, _("problem occurred while installing %s\n"),
newpkg->name);
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"error: problem occurred while installing %s\n",
newpkg->name);
}
}
/* make an install date (in UTC) */
newpkg->installdate = time(NULL);
_alpm_log(handle, ALPM_LOG_DEBUG, "updating database\n");
_alpm_log(handle, ALPM_LOG_DEBUG, "adding database entry '%s'\n", newpkg->name);
if(_alpm_local_db_write(db, newpkg, INFRQ_ALL)) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not update database entry %s-%s\n"),
newpkg->name, newpkg->version);
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"error: could not update database entry %s-%s\n",
newpkg->name, newpkg->version);
handle->pm_errno = ALPM_ERR_DB_WRITE;
return -1;
}
if(_alpm_db_add_pkgincache(db, newpkg) == -1) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not add entry '%s' in cache\n"),
newpkg->name);
}
PROGRESS(handle, progress, newpkg->name, 100, pkg_count, pkg_current);
switch(event.operation) {
case ALPM_PACKAGE_INSTALL:
alpm_logaction(handle, ALPM_CALLER_PREFIX, "installed %s (%s)\n",
newpkg->name, newpkg->version);
break;
case ALPM_PACKAGE_DOWNGRADE:
alpm_logaction(handle, ALPM_CALLER_PREFIX, "downgraded %s (%s -> %s)\n",
newpkg->name, oldpkg->version, newpkg->version);
break;
case ALPM_PACKAGE_REINSTALL:
alpm_logaction(handle, ALPM_CALLER_PREFIX, "reinstalled %s (%s)\n",
newpkg->name, newpkg->version);
break;
case ALPM_PACKAGE_UPGRADE:
alpm_logaction(handle, ALPM_CALLER_PREFIX, "upgraded %s (%s -> %s)\n",
newpkg->name, oldpkg->version, newpkg->version);
break;
default:
/* we should never reach here */
break;
}
/* run the post-install script if it exists */
if(alpm_pkg_has_scriptlet(newpkg)
&& !(trans->flags & ALPM_TRANS_FLAG_NOSCRIPTLET)) {
char *scriptlet = _alpm_local_db_pkgpath(db, newpkg, "install");
const char *scriptlet_name = is_upgrade ? "post_upgrade" : "post_install";
_alpm_runscriptlet(handle, scriptlet, scriptlet_name,
newpkg->version, oldpkg ? oldpkg->version : NULL, 0);
free(scriptlet);
}
event.type = ALPM_EVENT_PACKAGE_OPERATION_DONE;
EVENT(handle, &event);
return ret;
}
int _alpm_upgrade_packages(alpm_handle_t *handle)
{
size_t pkg_count, pkg_current;
int skip_ldconfig = 0, ret = 0;
alpm_list_t *targ;
alpm_trans_t *trans = handle->trans;
if(trans->add == NULL) {
return 0;
}
pkg_count = alpm_list_count(trans->add);
pkg_current = 1;
/* loop through our package list adding/upgrading one at a time */
for(targ = trans->add; targ; targ = targ->next) {
alpm_pkg_t *newpkg = targ->data;
if(handle->trans->state == STATE_INTERRUPTED) {
return ret;
}
if(commit_single_pkg(handle, newpkg, pkg_current, pkg_count)) {
/* something screwed up on the commit, abort the trans */
trans->state = STATE_INTERRUPTED;
handle->pm_errno = ALPM_ERR_TRANS_ABORT;
/* running ldconfig at this point could possibly screw system */
skip_ldconfig = 1;
ret = -1;
}
pkg_current++;
}
if(!skip_ldconfig) {
/* run ldconfig if it exists */
_alpm_ldconfig(handle);
}
return ret;
}

View file

@ -1,29 +0,0 @@
/*
* add.h
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef ALPM_ADD_H
#define ALPM_ADD_H
#include "db.h"
#include "alpm_list.h"
#include "trans.h"
int _alpm_upgrade_packages(alpm_handle_t *handle);
#endif /* ALPM_ADD_H */

View file

@ -1,135 +0,0 @@
/*
* alpm.c
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
* Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_LIBCURL
#include <curl/curl.h>
#endif
#include <errno.h>
#include <pwd.h>
/* libalpm */
#include "alpm.h"
#include "alpm_list.h"
#include "handle.h"
#include "log.h"
#include "util.h"
alpm_handle_t SYMEXPORT *alpm_initialize(const char *root, const char *dbpath,
alpm_errno_t *err)
{
alpm_errno_t myerr;
const char *lf = "db.lck";
char *hookdir;
size_t hookdirlen, lockfilelen;
struct passwd const *pw = NULL;
alpm_handle_t *myhandle = _alpm_handle_new();
if(myhandle == NULL) {
goto nomem;
}
if((myerr = _alpm_set_directory_option(root, &(myhandle->root), 1))) {
goto cleanup;
}
if((myerr = _alpm_set_directory_option(dbpath, &(myhandle->dbpath), 1))) {
goto cleanup;
}
/* to concatenate myhandle->root (ends with a slash) with SYSHOOKDIR (starts
* with a slash) correctly, we skip SYSHOOKDIR[0]; the regular +1 therefore
* disappears from the allocation */
hookdirlen = strlen(myhandle->root) + strlen(SYSHOOKDIR);
MALLOC(hookdir, hookdirlen, goto nomem);
snprintf(hookdir, hookdirlen, "%s%s", myhandle->root, &SYSHOOKDIR[1]);
myhandle->hookdirs = alpm_list_add(NULL, hookdir);
/* set default database extension */
STRDUP(myhandle->dbext, ".db", goto nomem);
lockfilelen = strlen(myhandle->dbpath) + strlen(lf) + 1;
MALLOC(myhandle->lockfile, lockfilelen, goto nomem);
snprintf(myhandle->lockfile, lockfilelen, "%s%s", myhandle->dbpath, lf);
if(_alpm_db_register_local(myhandle) == NULL) {
myerr = myhandle->pm_errno;
goto cleanup;
}
#ifdef HAVE_LIBCURL
curl_global_init(CURL_GLOBAL_ALL);
myhandle->curlm = curl_multi_init();
#endif
myhandle->parallel_downloads = 1;
/* set default sandboxuser */
ASSERT((pw = getpwuid(0)) != NULL, myerr = errno; goto cleanup);
STRDUP(myhandle->sandboxuser, pw->pw_name, goto nomem);
#ifdef ENABLE_NLS
bindtextdomain("libalpm", LOCALEDIR);
#endif
return myhandle;
nomem:
myerr = ALPM_ERR_MEMORY;
cleanup:
_alpm_handle_free(myhandle);
if(err) {
*err = myerr;
}
return NULL;
}
/* check current state and free all resources including storage locks */
int SYMEXPORT alpm_release(alpm_handle_t *myhandle)
{
CHECK_HANDLE(myhandle, return -1);
ASSERT(myhandle->trans == NULL, RET_ERR(myhandle, ALPM_ERR_TRANS_NOT_NULL, -1));
_alpm_handle_unlock(myhandle);
_alpm_handle_free(myhandle);
return 0;
}
const char SYMEXPORT *alpm_version(void)
{
return LIB_VERSION;
}
int SYMEXPORT alpm_capabilities(void)
{
return 0
#ifdef ENABLE_NLS
| ALPM_CAPABILITY_NLS
#endif
#ifdef HAVE_LIBCURL
| ALPM_CAPABILITY_DOWNLOADER
#endif
#ifdef HAVE_LIBGPGME
| ALPM_CAPABILITY_SIGNATURES
#endif
| 0;
}

File diff suppressed because it is too large Load diff

View file

@ -1,650 +0,0 @@
/*
* alpm_list.c
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
/* Note: alpm_list.{c,h} are intended to be standalone files. Do not include
* any other libalpm headers.
*/
/* libalpm */
#include "alpm_list.h"
/* check exported library symbols with: nm -C -D <lib> */
#define SYMEXPORT __attribute__((visibility("default")))
/* Allocation */
void SYMEXPORT alpm_list_free(alpm_list_t *list)
{
alpm_list_t *it = list;
while(it) {
alpm_list_t *tmp = it->next;
free(it);
it = tmp;
}
}
void SYMEXPORT alpm_list_free_inner(alpm_list_t *list, alpm_list_fn_free fn)
{
alpm_list_t *it = list;
if(fn) {
while(it) {
if(it->data) {
fn(it->data);
}
it = it->next;
}
}
}
/* Mutators */
alpm_list_t SYMEXPORT *alpm_list_add(alpm_list_t *list, void *data)
{
alpm_list_append(&list, data);
return list;
}
alpm_list_t SYMEXPORT *alpm_list_append(alpm_list_t **list, void *data)
{
alpm_list_t *ptr;
ptr = malloc(sizeof(alpm_list_t));
if(ptr == NULL) {
return NULL;
}
ptr->data = data;
ptr->next = NULL;
/* Special case: the input list is empty */
if(*list == NULL) {
*list = ptr;
ptr->prev = ptr;
} else {
alpm_list_t *lp = alpm_list_last(*list);
lp->next = ptr;
ptr->prev = lp;
(*list)->prev = ptr;
}
return ptr;
}
alpm_list_t SYMEXPORT *alpm_list_append_strdup(alpm_list_t **list, const char *data)
{
alpm_list_t *ret;
char *dup;
if((dup = strdup(data)) && (ret = alpm_list_append(list, dup))) {
return ret;
} else {
free(dup);
return NULL;
}
}
alpm_list_t SYMEXPORT *alpm_list_add_sorted(alpm_list_t *list, void *data, alpm_list_fn_cmp fn)
{
if(!fn || !list) {
return alpm_list_add(list, data);
} else {
alpm_list_t *add = NULL, *prev = NULL, *next = list;
add = malloc(sizeof(alpm_list_t));
if(add == NULL) {
return list;
}
add->data = data;
/* Find insertion point. */
while(next) {
if(fn(add->data, next->data) <= 0) break;
prev = next;
next = next->next;
}
/* Insert the add node to the list */
if(prev == NULL) { /* special case: we insert add as the first element */
add->prev = list->prev; /* list != NULL */
add->next = list;
list->prev = add;
return add;
} else if(next == NULL) { /* another special case: add last element */
add->prev = prev;
add->next = NULL;
prev->next = add;
list->prev = add;
return list;
} else {
add->prev = prev;
add->next = next;
next->prev = add;
prev->next = add;
return list;
}
}
}
alpm_list_t SYMEXPORT *alpm_list_join(alpm_list_t *first, alpm_list_t *second)
{
alpm_list_t *tmp;
if(first == NULL) {
return second;
}
if(second == NULL) {
return first;
}
/* tmp is the last element of the first list */
tmp = first->prev;
/* link the first list to the second */
tmp->next = second;
/* link the second list to the first */
first->prev = second->prev;
/* set the back reference to the tail */
second->prev = tmp;
return first;
}
alpm_list_t SYMEXPORT *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right,
alpm_list_fn_cmp fn)
{
alpm_list_t *newlist, *lp, *tail_ptr, *left_tail_ptr, *right_tail_ptr;
if(left == NULL) {
return right;
}
if(right == NULL) {
return left;
}
/* Save tail node pointers for future use */
left_tail_ptr = left->prev;
right_tail_ptr = right->prev;
if(fn(left->data, right->data) <= 0) {
newlist = left;
left = left->next;
}
else {
newlist = right;
right = right->next;
}
newlist->prev = NULL;
newlist->next = NULL;
lp = newlist;
while((left != NULL) && (right != NULL)) {
if(fn(left->data, right->data) <= 0) {
lp->next = left;
left->prev = lp;
left = left->next;
}
else {
lp->next = right;
right->prev = lp;
right = right->next;
}
lp = lp->next;
lp->next = NULL;
}
if(left != NULL) {
lp->next = left;
left->prev = lp;
tail_ptr = left_tail_ptr;
}
else if(right != NULL) {
lp->next = right;
right->prev = lp;
tail_ptr = right_tail_ptr;
}
else {
tail_ptr = lp;
}
newlist->prev = tail_ptr;
return newlist;
}
alpm_list_t SYMEXPORT *alpm_list_msort(alpm_list_t *list, size_t n,
alpm_list_fn_cmp fn)
{
if(n > 1) {
size_t half = n / 2;
size_t i = half - 1;
alpm_list_t *left = list, *lastleft = list, *right;
while(i--) {
lastleft = lastleft->next;
}
right = lastleft->next;
/* tidy new lists */
lastleft->next = NULL;
right->prev = left->prev;
left->prev = lastleft;
left = alpm_list_msort(left, half, fn);
right = alpm_list_msort(right, n - half, fn);
list = alpm_list_mmerge(left, right, fn);
}
return list;
}
alpm_list_t SYMEXPORT *alpm_list_remove_item(alpm_list_t *haystack,
alpm_list_t *item)
{
if(haystack == NULL || item == NULL) {
return haystack;
}
if(item == haystack) {
/* Special case: removing the head node which has a back reference to
* the tail node */
haystack = item->next;
if(haystack) {
haystack->prev = item->prev;
}
item->prev = NULL;
} else if(item == haystack->prev) {
/* Special case: removing the tail node, so we need to fix the back
* reference on the head node. We also know tail != head. */
if(item->prev) {
/* i->next should always be null */
item->prev->next = item->next;
haystack->prev = item->prev;
item->prev = NULL;
}
} else {
/* Normal case, non-head and non-tail node */
if(item->next) {
item->next->prev = item->prev;
}
if(item->prev) {
item->prev->next = item->next;
}
}
return haystack;
}
alpm_list_t SYMEXPORT *alpm_list_remove(alpm_list_t *haystack,
const void *needle, alpm_list_fn_cmp fn, void **data)
{
alpm_list_t *i = haystack;
if(data) {
*data = NULL;
}
if(needle == NULL) {
return haystack;
}
while(i) {
if(i->data == NULL) {
i = i->next;
continue;
}
if(fn(i->data, needle) == 0) {
haystack = alpm_list_remove_item(haystack, i);
if(data) {
*data = i->data;
}
free(i);
break;
} else {
i = i->next;
}
}
return haystack;
}
alpm_list_t SYMEXPORT *alpm_list_remove_str(alpm_list_t *haystack,
const char *needle, char **data)
{
return alpm_list_remove(haystack, (const void *)needle,
(alpm_list_fn_cmp)strcmp, (void **)data);
}
alpm_list_t SYMEXPORT *alpm_list_remove_dupes(const alpm_list_t *list)
{
const alpm_list_t *lp = list;
alpm_list_t *newlist = NULL;
while(lp) {
if(!alpm_list_find_ptr(newlist, lp->data)) {
if(alpm_list_append(&newlist, lp->data) == NULL) {
alpm_list_free(newlist);
return NULL;
}
}
lp = lp->next;
}
return newlist;
}
alpm_list_t SYMEXPORT *alpm_list_strdup(const alpm_list_t *list)
{
const alpm_list_t *lp = list;
alpm_list_t *newlist = NULL;
while(lp) {
if(alpm_list_append_strdup(&newlist, lp->data) == NULL) {
FREELIST(newlist);
return NULL;
}
lp = lp->next;
}
return newlist;
}
alpm_list_t SYMEXPORT *alpm_list_copy(const alpm_list_t *list)
{
const alpm_list_t *lp = list;
alpm_list_t *newlist = NULL;
while(lp) {
if(alpm_list_append(&newlist, lp->data) == NULL) {
alpm_list_free(newlist);
return NULL;
}
lp = lp->next;
}
return newlist;
}
alpm_list_t SYMEXPORT *alpm_list_copy_data(const alpm_list_t *list,
size_t size)
{
const alpm_list_t *lp = list;
alpm_list_t *newlist = NULL;
while(lp) {
void *newdata = malloc(size);
if(newdata) {
memcpy(newdata, lp->data, size);
if(alpm_list_append(&newlist, newdata) == NULL) {
free(newdata);
FREELIST(newlist);
return NULL;
}
lp = lp->next;
} else {
FREELIST(newlist);
return NULL;
}
}
return newlist;
}
alpm_list_t SYMEXPORT *alpm_list_reverse(alpm_list_t *list)
{
const alpm_list_t *lp;
alpm_list_t *newlist = NULL, *backup;
if(list == NULL) {
return NULL;
}
lp = alpm_list_last(list);
/* break our reverse circular list */
backup = list->prev;
list->prev = NULL;
while(lp) {
if(alpm_list_append(&newlist, lp->data) == NULL) {
alpm_list_free(newlist);
list->prev = backup;
return NULL;
}
lp = lp->prev;
}
list->prev = backup; /* restore tail pointer */
return newlist;
}
/* Accessors */
alpm_list_t SYMEXPORT *alpm_list_nth(const alpm_list_t *list, size_t n)
{
const alpm_list_t *i = list;
while(n--) {
i = i->next;
}
return (alpm_list_t *)i;
}
inline alpm_list_t SYMEXPORT *alpm_list_next(const alpm_list_t *node)
{
if(node) {
return node->next;
} else {
return NULL;
}
}
inline alpm_list_t SYMEXPORT *alpm_list_previous(const alpm_list_t *list)
{
if(list && list->prev->next) {
return list->prev;
} else {
return NULL;
}
}
alpm_list_t SYMEXPORT *alpm_list_last(const alpm_list_t *list)
{
if(list) {
return list->prev;
} else {
return NULL;
}
}
/* Misc */
size_t SYMEXPORT alpm_list_count(const alpm_list_t *list)
{
size_t i = 0;
const alpm_list_t *lp = list;
while(lp) {
++i;
lp = lp->next;
}
return i;
}
void SYMEXPORT *alpm_list_find(const alpm_list_t *haystack, const void *needle,
alpm_list_fn_cmp fn)
{
const alpm_list_t *lp = haystack;
while(lp) {
if(lp->data && fn(lp->data, needle) == 0) {
return lp->data;
}
lp = lp->next;
}
return NULL;
}
/* trivial helper function for alpm_list_find_ptr */
static int ptr_cmp(const void *p, const void *q)
{
return (p != q);
}
void SYMEXPORT *alpm_list_find_ptr(const alpm_list_t *haystack,
const void *needle)
{
return alpm_list_find(haystack, needle, ptr_cmp);
}
char SYMEXPORT *alpm_list_find_str(const alpm_list_t *haystack,
const char *needle)
{
return (char *)alpm_list_find(haystack, (const void *)needle,
(alpm_list_fn_cmp)strcmp);
}
int SYMEXPORT alpm_list_cmp_unsorted(const alpm_list_t *left,
const alpm_list_t *right, alpm_list_fn_cmp fn)
{
const alpm_list_t *l = left;
const alpm_list_t *r = right;
int *matched;
/* short circuiting length comparison */
while(l && r) {
l = l->next;
r = r->next;
}
if(l || r) {
return 0;
}
/* faster comparison for if the lists happen to be in the same order */
while(left && fn(left->data, right->data) == 0) {
left = left->next;
right = right->next;
}
if(!left) {
return 1;
}
matched = calloc(alpm_list_count(right), sizeof(int));
if(matched == NULL) {
return -1;
}
for(l = left; l; l = l->next) {
int found = 0;
int n = 0;
for(r = right; r; r = r->next, n++) {
/* make sure we don't match the same value twice */
if(matched[n]) {
continue;
}
if(fn(l->data, r->data) == 0) {
found = 1;
matched[n] = 1;
break;
}
}
if(!found) {
free(matched);
return 0;
}
}
free(matched);
return 1;
}
void SYMEXPORT alpm_list_diff_sorted(const alpm_list_t *left,
const alpm_list_t *right, alpm_list_fn_cmp fn,
alpm_list_t **onlyleft, alpm_list_t **onlyright)
{
const alpm_list_t *l = left;
const alpm_list_t *r = right;
if(!onlyleft && !onlyright) {
return;
}
while(l != NULL && r != NULL) {
int cmp = fn(l->data, r->data);
if(cmp < 0) {
if(onlyleft) {
*onlyleft = alpm_list_add(*onlyleft, l->data);
}
l = l->next;
}
else if(cmp > 0) {
if(onlyright) {
*onlyright = alpm_list_add(*onlyright, r->data);
}
r = r->next;
} else {
l = l->next;
r = r->next;
}
}
while(l != NULL) {
if(onlyleft) {
*onlyleft = alpm_list_add(*onlyleft, l->data);
}
l = l->next;
}
while(r != NULL) {
if(onlyright) {
*onlyright = alpm_list_add(*onlyright, r->data);
}
r = r->next;
}
}
alpm_list_t SYMEXPORT *alpm_list_diff(const alpm_list_t *lhs,
const alpm_list_t *rhs, alpm_list_fn_cmp fn)
{
alpm_list_t *left, *right;
alpm_list_t *ret = NULL;
left = alpm_list_copy(lhs);
left = alpm_list_msort(left, alpm_list_count(left), fn);
right = alpm_list_copy(rhs);
right = alpm_list_msort(right, alpm_list_count(right), fn);
alpm_list_diff_sorted(left, right, fn, &ret, NULL);
alpm_list_free(left);
alpm_list_free(right);
return ret;
}
void SYMEXPORT *alpm_list_to_array(const alpm_list_t *list, size_t n,
size_t size)
{
size_t i;
const alpm_list_t *item;
char *array;
if(n == 0) {
return NULL;
}
array = malloc(n * size);
if(array == NULL) {
return NULL;
}
for(i = 0, item = list; i < n && item; i++, item = item->next) {
memcpy(array + i * size, item->data, size);
}
return array;
}

View file

@ -1,395 +0,0 @@
/*
* alpm_list.h
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef ALPM_LIST_H
#define ALPM_LIST_H
#include <stdlib.h> /* size_t */
/* Note: alpm_list.{c,h} are intended to be standalone files. Do not include
* any other libalpm headers.
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ingroup libalpm
* @addtogroup libalpm_list libalpm_list(3)
* @brief Functions to manipulate alpm_list_t lists.
*
* These functions are designed to create, destroy, and modify lists of
* type alpm_list_t. This is an internal list type used by libalpm that is
* publicly exposed for use by frontends if desired.
*
* It is exposed so front ends can use it to prevent the need to reimplement
* lists of their own; however, it is not required that the front end uses
* it.
* @{
*/
/** A doubly linked list */
typedef struct _alpm_list_t {
/** data held by the list node */
void *data;
/** pointer to the previous node */
struct _alpm_list_t *prev;
/** pointer to the next node */
struct _alpm_list_t *next;
} alpm_list_t;
/** Frees a list and its contents */
#define FREELIST(p) do { alpm_list_free_inner(p, free); alpm_list_free(p); p = NULL; } while(0)
/** item deallocation callback.
* @param item the item to free
*/
typedef void (*alpm_list_fn_free)(void * item);
/** item comparison callback */
typedef int (*alpm_list_fn_cmp)(const void *, const void *);
/* allocation */
/** Free a list, but not the contained data.
*
* @param list the list to free
*/
void alpm_list_free(alpm_list_t *list);
/** Free the internal data of a list structure but not the list itself.
*
* @param list the list to free
* @param fn a free function for the internal data
*/
void alpm_list_free_inner(alpm_list_t *list, alpm_list_fn_free fn);
/* item mutators */
/** Add a new item to the end of the list.
*
* @param list the list to add to
* @param data the new item to be added to the list
*
* @return the resultant list
*/
alpm_list_t *alpm_list_add(alpm_list_t *list, void *data);
/**
* @brief Add a new item to the end of the list.
*
* @param list the list to add to
* @param data the new item to be added to the list
*
* @return the newly added item
*/
alpm_list_t *alpm_list_append(alpm_list_t **list, void *data);
/**
* @brief Duplicate and append a string to a list.
*
* @param list the list to append to
* @param data the string to duplicate and append
*
* @return the newly added item
*/
alpm_list_t *alpm_list_append_strdup(alpm_list_t **list, const char *data);
/**
* @brief Add items to a list in sorted order.
*
* @param list the list to add to
* @param data the new item to be added to the list
* @param fn the comparison function to use to determine order
*
* @return the resultant list
*/
alpm_list_t *alpm_list_add_sorted(alpm_list_t *list, void *data, alpm_list_fn_cmp fn);
/**
* @brief Join two lists.
* The two lists must be independent. Do not free the original lists after
* calling this function, as this is not a copy operation. The list pointers
* passed in should be considered invalid after calling this function.
*
* @param first the first list
* @param second the second list
*
* @return the resultant joined list
*/
alpm_list_t *alpm_list_join(alpm_list_t *first, alpm_list_t *second);
/**
* @brief Merge the two sorted sublists into one sorted list.
*
* @param left the first list
* @param right the second list
* @param fn comparison function for determining merge order
*
* @return the resultant list
*/
alpm_list_t *alpm_list_mmerge(alpm_list_t *left, alpm_list_t *right, alpm_list_fn_cmp fn);
/**
* @brief Sort a list of size `n` using mergesort algorithm.
*
* @param list the list to sort
* @param n the size of the list
* @param fn the comparison function for determining order
*
* @return the resultant list
*/
alpm_list_t *alpm_list_msort(alpm_list_t *list, size_t n, alpm_list_fn_cmp fn);
/**
* @brief Remove an item from the list.
* item is not freed; this is the responsibility of the caller.
*
* @param haystack the list to remove the item from
* @param item the item to remove from the list
*
* @return the resultant list
*/
alpm_list_t *alpm_list_remove_item(alpm_list_t *haystack, alpm_list_t *item);
/**
* @brief Remove an item from the list.
*
* @param haystack the list to remove the item from
* @param needle the data member of the item we're removing
* @param fn the comparison function for searching
* @param data output parameter containing data of the removed item
*
* @return the resultant list
*/
alpm_list_t *alpm_list_remove(alpm_list_t *haystack, const void *needle, alpm_list_fn_cmp fn, void **data);
/**
* @brief Remove a string from a list.
*
* @param haystack the list to remove the item from
* @param needle the data member of the item we're removing
* @param data output parameter containing data of the removed item
*
* @return the resultant list
*/
alpm_list_t *alpm_list_remove_str(alpm_list_t *haystack, const char *needle, char **data);
/**
* @brief Create a new list without any duplicates.
*
* This does NOT copy data members.
*
* @param list the list to copy
*
* @return a new list containing non-duplicate items
*/
alpm_list_t *alpm_list_remove_dupes(const alpm_list_t *list);
/**
* @brief Copy a string list, including data.
*
* @param list the list to copy
*
* @return a copy of the original list
*/
alpm_list_t *alpm_list_strdup(const alpm_list_t *list);
/**
* @brief Copy a list, without copying data.
*
* @param list the list to copy
*
* @return a copy of the original list
*/
alpm_list_t *alpm_list_copy(const alpm_list_t *list);
/**
* @brief Copy a list and copy the data.
* Note that the data elements to be copied should not contain pointers
* and should also be of constant size.
*
* @param list the list to copy
* @param size the size of each data element
*
* @return a copy of the original list, data copied as well
*/
alpm_list_t *alpm_list_copy_data(const alpm_list_t *list, size_t size);
/**
* @brief Create a new list in reverse order.
*
* @param list the list to copy
*
* @return a new list in reverse order
*/
alpm_list_t *alpm_list_reverse(alpm_list_t *list);
/* item accessors */
/**
* @brief Return nth element from list (starting from 0).
*
* @param list the list
* @param n the index of the item to find (n < alpm_list_count(list) IS needed)
*
* @return an alpm_list_t node for index `n`
*/
alpm_list_t *alpm_list_nth(const alpm_list_t *list, size_t n);
/**
* @brief Get the next element of a list.
*
* @param list the list node
*
* @return the next element, or NULL when no more elements exist
*/
alpm_list_t *alpm_list_next(const alpm_list_t *list);
/**
* @brief Get the previous element of a list.
*
* @param list the list head
*
* @return the previous element, or NULL when no previous element exist
*/
alpm_list_t *alpm_list_previous(const alpm_list_t *list);
/**
* @brief Get the last item in the list.
*
* @param list the list
*
* @return the last element in the list
*/
alpm_list_t *alpm_list_last(const alpm_list_t *list);
/* misc */
/**
* @brief Get the number of items in a list.
*
* @param list the list
*
* @return the number of list items
*/
size_t alpm_list_count(const alpm_list_t *list);
/**
* @brief Find an item in a list.
*
* @param needle the item to search
* @param haystack the list
* @param fn the comparison function for searching (!= NULL)
*
* @return `needle` if found, NULL otherwise
*/
void *alpm_list_find(const alpm_list_t *haystack, const void *needle, alpm_list_fn_cmp fn);
/**
* @brief Find an item in a list.
*
* Search for the item whose data matches that of the `needle`.
*
* @param needle the data to search for (== comparison)
* @param haystack the list
*
* @return `needle` if found, NULL otherwise
*/
void *alpm_list_find_ptr(const alpm_list_t *haystack, const void *needle);
/**
* @brief Find a string in a list.
*
* @param needle the string to search for
* @param haystack the list
*
* @return `needle` if found, NULL otherwise
*/
char *alpm_list_find_str(const alpm_list_t *haystack, const char *needle);
/**
* @brief Check if two lists contain the same data, ignoring order.
*
* Lists are considered equal if they both contain the same data regardless
* of order.
*
* @param left the first list
* @param right the second list
* @param fn the comparison function
*
* @return 1 if the lists are equal, 0 if not equal, -1 on error.
*/
int alpm_list_cmp_unsorted(const alpm_list_t *left,
const alpm_list_t *right, alpm_list_fn_cmp fn);
/**
* @brief Find the differences between list `left` and list `right`
*
* The two lists must be sorted. Items only in list `left` are added to the
* `onlyleft` list. Items only in list `right` are added to the `onlyright`
* list.
*
* @param left the first list
* @param right the second list
* @param fn the comparison function
* @param onlyleft pointer to the first result list
* @param onlyright pointer to the second result list
*
*/
void alpm_list_diff_sorted(const alpm_list_t *left, const alpm_list_t *right,
alpm_list_fn_cmp fn, alpm_list_t **onlyleft, alpm_list_t **onlyright);
/**
* @brief Find the items in list `lhs` that are not present in list `rhs`.
*
* @param lhs the first list
* @param rhs the second list
* @param fn the comparison function
*
* @return a list containing all items in `lhs` not present in `rhs`
*/
alpm_list_t *alpm_list_diff(const alpm_list_t *lhs, const alpm_list_t *rhs, alpm_list_fn_cmp fn);
/**
* @brief Copy a list and data into a standard C array of fixed length.
* Note that the data elements are shallow copied so any contained pointers
* will point to the original data.
*
* @param list the list to copy
* @param n the size of the list
* @param size the size of each data element
*
* @return an array version of the original list, data copied as well
*/
void *alpm_list_to_array(const alpm_list_t *list, size_t n, size_t size);
/* End of alpm_list */
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* ALPM_LIST_H */

View file

@ -1,100 +0,0 @@
/*
* backup.c
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2005 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
* Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
/* libalpm */
#include "backup.h"
#include "alpm_list.h"
#include "log.h"
#include "util.h"
/* split a backup string "file\thash" into the relevant components */
int _alpm_split_backup(const char *string, alpm_backup_t **backup)
{
char *str, *ptr;
STRDUP(str, string, return -1);
/* tab delimiter */
ptr = str ? strchr(str, '\t') : NULL;
if(ptr == NULL) {
(*backup)->name = str;
(*backup)->hash = NULL;
return 0;
}
*ptr = '\0';
ptr++;
/* now str points to the filename and ptr points to the hash */
STRDUP((*backup)->name, str, FREE(str); return -1);
STRDUP((*backup)->hash, ptr, FREE((*backup)->name); FREE(str); return -1);
FREE(str);
return 0;
}
/* Look for a filename in a alpm_pkg_t.backup list. If we find it,
* then we return the full backup entry.
*/
alpm_backup_t *_alpm_needbackup(const char *file, alpm_pkg_t *pkg)
{
const alpm_list_t *lp;
if(file == NULL || pkg == NULL) {
return NULL;
}
for(lp = alpm_pkg_get_backup(pkg); lp; lp = lp->next) {
alpm_backup_t *backup = lp->data;
if(strcmp(file, backup->name) == 0) {
return backup;
}
}
return NULL;
}
void _alpm_backup_free(alpm_backup_t *backup)
{
ASSERT(backup != NULL, return);
FREE(backup->name);
FREE(backup->hash);
FREE(backup);
}
alpm_backup_t *_alpm_backup_dup(const alpm_backup_t *backup)
{
alpm_backup_t *newbackup;
CALLOC(newbackup, 1, sizeof(alpm_backup_t), return NULL);
STRDUP(newbackup->name, backup->name, goto error);
STRDUP(newbackup->hash, backup->hash, goto error);
return newbackup;
error:
free(newbackup->name);
free(newbackup);
return NULL;
}

View file

@ -1,196 +0,0 @@
/*
* RFC 1521 base64 encoding/decoding
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
/*
* Pacman Notes:
*
* Taken from the PolarSSL project at www.polarssl.org under terms of the
* GPL. This is from version 0.14.2 of the library, and has been modified
* as following, which may be helpful for future updates:
* * remove "polarssl/config.h" include
* * change include from "polarssl/base64.h" to "base64.h"
* * removal of SELF_TEST code
*/
#include <stdint.h>
#include "base64.h"
#if 0
static const unsigned char base64_enc_map[64] =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '+', '/'
};
#endif
static const unsigned char base64_dec_map[128] =
{
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 127, 127, 127, 127, 127
};
#if 0
/*
* Encode a buffer into base64 format
*/
int base64_encode( unsigned char *dst, size_t *dlen,
const unsigned char *src, size_t slen )
{
size_t i, n;
int C1, C2, C3;
unsigned char *p;
if( slen == 0 )
return( 0 );
n = (slen << 3) / 6;
switch( (slen << 3) - (n * 6) )
{
case 2: n += 3; break;
case 4: n += 2; break;
default: break;
}
if( *dlen < n + 1 )
{
*dlen = n + 1;
return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
}
n = (slen / 3) * 3;
for( i = 0, p = dst; i < n; i += 3 )
{
C1 = *src++;
C2 = *src++;
C3 = *src++;
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
*p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
*p++ = base64_enc_map[C3 & 0x3F];
}
if( i < slen )
{
C1 = *src++;
C2 = ((i + 1) < slen) ? *src++ : 0;
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
if( (i + 1) < slen )
*p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
else *p++ = '=';
*p++ = '=';
}
*dlen = p - dst;
*p = 0;
return( 0 );
}
#endif
/*
* Decode a base64-formatted buffer
*/
int base64_decode( unsigned char *dst, size_t *dlen,
const unsigned char *src, size_t slen )
{
size_t i, n;
uint32_t j, x;
unsigned char *p;
for( i = j = n = 0; i < slen; i++ )
{
if( ( slen - i ) >= 2 &&
src[i] == '\r' && src[i + 1] == '\n' )
continue;
if( src[i] == '\n' )
continue;
if( src[i] == '=' && ++j > 2 )
return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
if( base64_dec_map[src[i]] < 64 && j != 0 )
return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
n++;
}
if( n == 0 )
return( 0 );
n = ((n * 6) + 7) >> 3;
if( *dlen < n )
{
*dlen = n;
return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
}
for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
{
if( *src == '\r' || *src == '\n' )
continue;
j -= ( base64_dec_map[*src] == 64 );
x = (x << 6) | ( base64_dec_map[*src] & 0x3F );
if( ++n == 4 )
{
n = 0;
if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
if( j > 2 ) *p++ = (unsigned char)( x );
}
}
*dlen = p - dst;
return( 0 );
}

View file

@ -1,72 +0,0 @@
/**
* \file base64.h
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef BASE64_H
#define BASE64_H
#include <string.h>
#define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL -0x0010 /**< Output buffer too small. */
#define POLARSSL_ERR_BASE64_INVALID_CHARACTER -0x0012 /**< Invalid character in input. */
#if 0
/**
* \brief Encode a buffer into base64 format
*
* \param dst destination buffer
* \param dlen size of the buffer
* \param src source buffer
* \param slen amount of data to be encoded
*
* \return 0 if successful, or POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL.
* *dlen is always updated to reflect the amount
* of data that has (or would have) been written.
*
* \note Call this function with *dlen = 0 to obtain the
* required buffer size in *dlen
*/
int base64_encode( unsigned char *dst, size_t *dlen,
const unsigned char *src, size_t slen );
#endif
/**
* \brief Decode a base64-formatted buffer
*
* \param dst destination buffer
* \param dlen size of the buffer
* \param src source buffer
* \param slen amount of data to be decoded
*
* \return 0 if successful, POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL, or
* POLARSSL_ERR_BASE64_INVALID_DATA if the input data is not
* correct. *dlen is always updated to reflect the amount
* of data that has (or would have) been written.
*
* \note Call this function with *dlen = 0 to obtain the
* required buffer size in *dlen
*/
int base64_decode( unsigned char *dst, size_t *dlen,
const unsigned char *src, size_t slen );
#endif /* base64.h */

File diff suppressed because it is too large Load diff

View file

@ -1,789 +0,0 @@
/*
* be_package.c : backend for packages
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
/* libarchive */
#include <archive.h>
#include <archive_entry.h>
/* libalpm */
#include "alpm_list.h"
#include "alpm.h"
#include "libarchive-compat.h"
#include "util.h"
#include "log.h"
#include "handle.h"
#include "package.h"
#include "deps.h"
#include "filelist.h"
#include "util.h"
struct package_changelog {
struct archive *archive;
int fd;
};
/**
* Open a package changelog for reading. Similar to fopen in functionality,
* except that the returned 'file stream' is from an archive.
* @param pkg the package (file) to read the changelog
* @return a 'file stream' to the package changelog
*/
static void *_package_changelog_open(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
struct package_changelog *changelog;
struct archive *archive;
struct archive_entry *entry;
const char *pkgfile = pkg->origin_data.file;
struct stat buf;
int fd;
fd = _alpm_open_archive(pkg->handle, pkgfile, &buf,
&archive, ALPM_ERR_PKG_OPEN);
if(fd < 0) {
return NULL;
}
while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
const char *entry_name = archive_entry_pathname(entry);
if(strcmp(entry_name, ".CHANGELOG") == 0) {
changelog = malloc(sizeof(struct package_changelog));
if(!changelog) {
pkg->handle->pm_errno = ALPM_ERR_MEMORY;
_alpm_archive_read_free(archive);
close(fd);
return NULL;
}
changelog->archive = archive;
changelog->fd = fd;
return changelog;
}
}
/* we didn't find a changelog */
_alpm_archive_read_free(archive);
close(fd);
errno = ENOENT;
return NULL;
}
/**
* Read data from an open changelog 'file stream'. Similar to fread in
* functionality, this function takes a buffer and amount of data to read.
* @param ptr a buffer to fill with raw changelog data
* @param size the size of the buffer
* @param pkg the package that the changelog is being read from
* @param fp a 'file stream' to the package changelog
* @return the number of characters read, or 0 if there is no more data
*/
static size_t _package_changelog_read(void *ptr, size_t size,
const alpm_pkg_t UNUSED *pkg, void *fp)
{
struct package_changelog *changelog = fp;
ssize_t sret = archive_read_data(changelog->archive, ptr, size);
/* Report error (negative values) */
if(sret < 0) {
RET_ERR(pkg->handle, ALPM_ERR_LIBARCHIVE, 0);
} else {
return (size_t)sret;
}
}
/**
* Close a package changelog for reading. Similar to fclose in functionality,
* except that the 'file stream' is from an archive.
* @param pkg the package (file) that the changelog was read from
* @param fp a 'file stream' to the package changelog
* @return whether closing the package changelog stream was successful
*/
static int _package_changelog_close(const alpm_pkg_t UNUSED *pkg, void *fp)
{
int ret;
struct package_changelog *changelog = fp;
ret = _alpm_archive_read_free(changelog->archive);
close(changelog->fd);
free(changelog);
return ret;
}
/** Package file operations struct accessor. We implement this as a method
* because we want to reuse the majority of the default_pkg_ops struct and
* add only a few operations of our own on top.
*/
static const struct pkg_operations *get_file_pkg_ops(void)
{
static struct pkg_operations file_pkg_ops;
static int file_pkg_ops_initialized = 0;
if(!file_pkg_ops_initialized) {
file_pkg_ops = default_pkg_ops;
file_pkg_ops.changelog_open = _package_changelog_open;
file_pkg_ops.changelog_read = _package_changelog_read;
file_pkg_ops.changelog_close = _package_changelog_close;
file_pkg_ops_initialized = 1;
}
return &file_pkg_ops;
}
/**
* Parses the package description file for a package into a alpm_pkg_t struct.
* @param archive the archive to read from, pointed at the .PKGINFO entry
* @param newpkg an empty alpm_pkg_t struct to fill with package info
*
* @return 0 on success, -1 on error
*/
static int parse_descfile(alpm_handle_t *handle, struct archive *a, alpm_pkg_t *newpkg)
{
char *ptr = NULL;
char *key = NULL;
int ret, linenum = 0;
struct archive_read_buffer buf = {0};
/* 512K for a line length seems reasonable */
buf.max_line_size = 512 * 1024;
/* loop until we reach EOF or other error */
while((ret = _alpm_archive_fgets(a, &buf)) == ARCHIVE_OK) {
size_t len = _alpm_strip_newline(buf.line, buf.real_line_size);
linenum++;
key = buf.line;
if(len == 0 || key[0] == '#') {
continue;
}
/* line is always in this format: "key = value"
* we can be sure the " = " exists, so look for that */
ptr = memchr(key, ' ', len);
if(!ptr || (size_t)(ptr - key + 2) > len || memcmp(ptr, " = ", 3) != 0) {
_alpm_log(handle, ALPM_LOG_DEBUG,
"%s: syntax error in description file line %d\n",
newpkg->name ? newpkg->name : "error", linenum);
} else {
/* NULL the end of the key portion, move ptr to start of value */
*ptr = '\0';
ptr += 3;
if(strcmp(key, "pkgname") == 0) {
STRDUP(newpkg->name, ptr, return -1);
newpkg->name_hash = _alpm_hash_sdbm(newpkg->name);
} else if(strcmp(key, "pkgbase") == 0) {
STRDUP(newpkg->base, ptr, return -1);
} else if(strcmp(key, "pkgver") == 0) {
STRDUP(newpkg->version, ptr, return -1);
} else if(strcmp(key, "basever") == 0) {
/* not used atm */
} else if(strcmp(key, "pkgdesc") == 0) {
STRDUP(newpkg->desc, ptr, return -1);
} else if(strcmp(key, "group") == 0) {
char *tmp = NULL;
STRDUP(tmp, ptr, return -1);
newpkg->groups = alpm_list_add(newpkg->groups, tmp);
} else if(strcmp(key, "url") == 0) {
STRDUP(newpkg->url, ptr, return -1);
} else if(strcmp(key, "license") == 0) {
char *tmp = NULL;
STRDUP(tmp, ptr, return -1);
newpkg->licenses = alpm_list_add(newpkg->licenses, tmp);
} else if(strcmp(key, "builddate") == 0) {
newpkg->builddate = _alpm_parsedate(ptr);
} else if(strcmp(key, "packager") == 0) {
STRDUP(newpkg->packager, ptr, return -1);
} else if(strcmp(key, "arch") == 0) {
STRDUP(newpkg->arch, ptr, return -1);
} else if(strcmp(key, "size") == 0) {
/* size in the raw package is uncompressed (installed) size */
newpkg->isize = _alpm_strtoofft(ptr);
} else if(strcmp(key, "depend") == 0) {
alpm_depend_t *dep = alpm_dep_from_string(ptr);
newpkg->depends = alpm_list_add(newpkg->depends, dep);
} else if(strcmp(key, "optdepend") == 0) {
alpm_depend_t *optdep = alpm_dep_from_string(ptr);
newpkg->optdepends = alpm_list_add(newpkg->optdepends, optdep);
} else if(strcmp(key, "makedepend") == 0) {
alpm_depend_t *makedep = alpm_dep_from_string(ptr);
newpkg->makedepends = alpm_list_add(newpkg->makedepends, makedep);
} else if(strcmp(key, "checkdepend") == 0) {
alpm_depend_t *checkdep = alpm_dep_from_string(ptr);
newpkg->checkdepends = alpm_list_add(newpkg->checkdepends, checkdep);
} else if(strcmp(key, "conflict") == 0) {
alpm_depend_t *conflict = alpm_dep_from_string(ptr);
newpkg->conflicts = alpm_list_add(newpkg->conflicts, conflict);
} else if(strcmp(key, "replaces") == 0) {
alpm_depend_t *replace = alpm_dep_from_string(ptr);
newpkg->replaces = alpm_list_add(newpkg->replaces, replace);
} else if(strcmp(key, "provides") == 0) {
alpm_depend_t *provide = alpm_dep_from_string(ptr);
newpkg->provides = alpm_list_add(newpkg->provides, provide);
} else if(strcmp(key, "backup") == 0) {
alpm_backup_t *backup;
CALLOC(backup, 1, sizeof(alpm_backup_t), return -1);
STRDUP(backup->name, ptr, FREE(backup); return -1);
newpkg->backup = alpm_list_add(newpkg->backup, backup);
} else if(strcmp(key, "xdata") == 0) {
alpm_pkg_xdata_t *pd = _alpm_pkg_parse_xdata(ptr);
if(pd == NULL || !alpm_list_append(&newpkg->xdata, pd)) {
_alpm_pkg_xdata_free(pd);
return -1;
}
} else {
const char *pkgname = newpkg->name ? newpkg->name : "error";
_alpm_log(handle, ALPM_LOG_WARNING, _("%s: unknown key '%s' in package description\n"), pkgname, key);
_alpm_log(handle, ALPM_LOG_DEBUG, "%s: unknown key '%s' in description file line %d\n",
pkgname, key, linenum);
}
}
}
if(ret != ARCHIVE_EOF) {
_alpm_log(handle, ALPM_LOG_DEBUG, "error parsing package descfile\n");
return -1;
}
return 0;
}
/**
* Validate a package.
* @param handle the context handle
* @param pkgfile path to the package file
* @param syncpkg package object to load verification data from (md5sum,
* sha256sum, and/or base64 signature)
* @param level the required level of signature verification
* @param sigdata signature data from the package to pass back
* @param validation successful validations performed on the package file
* @return 0 if package is fully valid, -1 and pm_errno otherwise
*/
int _alpm_pkg_validate_internal(alpm_handle_t *handle,
const char *pkgfile, alpm_pkg_t *syncpkg, int level,
alpm_siglist_t **sigdata, int *validation)
{
int has_sig;
handle->pm_errno = ALPM_ERR_OK;
if(pkgfile == NULL || strlen(pkgfile) == 0) {
RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1);
}
/* attempt to access the package file, ensure it exists */
if(_alpm_access(handle, NULL, pkgfile, R_OK) != 0) {
if(errno == ENOENT) {
handle->pm_errno = ALPM_ERR_PKG_NOT_FOUND;
} else if(errno == EACCES) {
handle->pm_errno = ALPM_ERR_BADPERMS;
} else {
handle->pm_errno = ALPM_ERR_PKG_OPEN;
}
return -1;
}
/* can we get away with skipping checksums? */
has_sig = 0;
if(level & ALPM_SIG_PACKAGE) {
if(syncpkg && syncpkg->base64_sig) {
has_sig = 1;
} else {
char *sigpath = _alpm_sigpath(handle, pkgfile);
if(sigpath && !_alpm_access(handle, NULL, sigpath, R_OK)) {
has_sig = 1;
}
free(sigpath);
}
}
if(syncpkg && (!has_sig || !syncpkg->base64_sig)) {
if(syncpkg->md5sum && !syncpkg->sha256sum) {
_alpm_log(handle, ALPM_LOG_DEBUG, "md5sum: %s\n", syncpkg->md5sum);
_alpm_log(handle, ALPM_LOG_DEBUG, "checking md5sum for %s\n", pkgfile);
if(_alpm_test_checksum(pkgfile, syncpkg->md5sum, ALPM_PKG_VALIDATION_MD5SUM) != 0) {
RET_ERR(handle, ALPM_ERR_PKG_INVALID_CHECKSUM, -1);
}
if(validation) {
*validation |= ALPM_PKG_VALIDATION_MD5SUM;
}
}
if(syncpkg->sha256sum) {
_alpm_log(handle, ALPM_LOG_DEBUG, "sha256sum: %s\n", syncpkg->sha256sum);
_alpm_log(handle, ALPM_LOG_DEBUG, "checking sha256sum for %s\n", pkgfile);
if(_alpm_test_checksum(pkgfile, syncpkg->sha256sum, ALPM_PKG_VALIDATION_SHA256SUM) != 0) {
RET_ERR(handle, ALPM_ERR_PKG_INVALID_CHECKSUM, -1);
}
if(validation) {
*validation |= ALPM_PKG_VALIDATION_SHA256SUM;
}
}
}
/* even if we don't have a sig, run the check code if level tells us to */
if(level & ALPM_SIG_PACKAGE) {
const char *sig = syncpkg ? syncpkg->base64_sig : NULL;
_alpm_log(handle, ALPM_LOG_DEBUG, "sig data: %s\n", sig ? sig : "<from .sig>");
if(!has_sig && !(level & ALPM_SIG_PACKAGE_OPTIONAL)) {
handle->pm_errno = ALPM_ERR_PKG_MISSING_SIG;
return -1;
}
if(_alpm_check_pgp_helper(handle, pkgfile, sig,
level & ALPM_SIG_PACKAGE_OPTIONAL, level & ALPM_SIG_PACKAGE_MARGINAL_OK,
level & ALPM_SIG_PACKAGE_UNKNOWN_OK, sigdata)) {
handle->pm_errno = ALPM_ERR_PKG_INVALID_SIG;
return -1;
}
if(validation && has_sig) {
*validation |= ALPM_PKG_VALIDATION_SIGNATURE;
}
}
if(validation && !*validation) {
*validation = ALPM_PKG_VALIDATION_NONE;
}
return 0;
}
/**
* Handle the existence of simple paths for _alpm_load_pkg_internal()
* @param pkg package to change
* @param path path to examine
* @return 0 if path doesn't match any rule, 1 if it has been handled
*/
static int handle_simple_path(alpm_pkg_t *pkg, const char *path)
{
if(strcmp(path, ".INSTALL") == 0) {
pkg->scriptlet = 1;
return 1;
} else if(*path == '.') {
/* for now, ignore all files starting with '.' that haven't
* already been handled (for future possibilities) */
return 1;
}
return 0;
}
/**
* Add a file to the files list for pkg.
*
* @param pkg package to add the file to
* @param files_size size of pkg->files.files
* @param entry archive entry of the file to add to the list
* @param path path of the file to be added
* @return <0 on error, 0 on success
*/
static int add_entry_to_files_list(alpm_filelist_t *filelist,
size_t *files_size, struct archive_entry *entry, const char *path)
{
const size_t files_count = filelist->count;
alpm_file_t *current_file;
mode_t type;
size_t pathlen;
if(!_alpm_greedy_grow((void **)&filelist->files,
files_size, (files_count + 1) * sizeof(alpm_file_t))) {
return -1;
}
type = archive_entry_filetype(entry);
pathlen = strlen(path);
current_file = filelist->files + files_count;
/* mtree paths don't contain a tailing slash, those we get from
* the archive directly do (expensive way)
* Other code relies on it to detect directories so add it here.*/
if(type == AE_IFDIR && path[pathlen - 1] != '/') {
/* 2 = 1 for / + 1 for \0 */
char *newpath;
MALLOC(newpath, pathlen + 2, return -1);
strcpy(newpath, path);
newpath[pathlen] = '/';
newpath[pathlen + 1] = '\0';
current_file->name = newpath;
} else {
STRDUP(current_file->name, path, return -1);
}
current_file->size = archive_entry_size(entry);
current_file->mode = archive_entry_mode(entry);
filelist->count++;
return 0;
}
/**
* Generate a new file list from an mtree file and add it to the package.
* An existing file list will be free()d first.
*
* archive should point to an archive struct which is already at the
* position of the mtree's header.
*
* @param handle
* @param pkg package to add the file list to
* @param archive archive containing the mtree
* @return 0 on success, <0 on error
*/
static int build_filelist_from_mtree(alpm_handle_t *handle, alpm_pkg_t *pkg, struct archive *archive)
{
int ret = 0;
size_t i;
size_t mtree_maxsize = 0;
size_t mtree_cursize = 0;
size_t files_size = 0; /* we clean up the existing array so this is fine */
char *mtree_data = NULL;
struct archive *mtree;
struct archive_entry *mtree_entry = NULL;
alpm_filelist_t filelist = {0};
_alpm_log(handle, ALPM_LOG_DEBUG,
"found mtree for package %s, getting file list\n", pkg->filename);
/* create a new archive to parse the mtree and load it from archive into memory */
/* TODO: split this into a function */
if((mtree = archive_read_new()) == NULL) {
GOTO_ERR(handle, ALPM_ERR_LIBARCHIVE, error);
}
_alpm_archive_read_support_filter_all(mtree);
archive_read_support_format_mtree(mtree);
/* TODO: split this into a function */
while(1) {
ssize_t size;
if(!_alpm_greedy_grow((void **)&mtree_data, &mtree_maxsize, mtree_cursize + ALPM_BUFFER_SIZE)) {
goto error;
}
size = archive_read_data(archive, mtree_data + mtree_cursize, ALPM_BUFFER_SIZE);
if(size < 0) {
_alpm_log(handle, ALPM_LOG_DEBUG, _("error while reading package %s: %s\n"),
pkg->filename, archive_error_string(archive));
GOTO_ERR(handle, ALPM_ERR_LIBARCHIVE, error);
}
if(size == 0) {
break;
}
mtree_cursize += size;
}
if(archive_read_open_memory(mtree, mtree_data, mtree_cursize)) {
_alpm_log(handle, ALPM_LOG_DEBUG,
_("error while reading mtree of package %s: %s\n"),
pkg->filename, archive_error_string(mtree));
GOTO_ERR(handle, ALPM_ERR_LIBARCHIVE, error);
}
while((ret = archive_read_next_header(mtree, &mtree_entry)) == ARCHIVE_OK) {
const char *path = archive_entry_pathname(mtree_entry);
/* strip leading "./" from path entries */
if(path[0] == '.' && path[1] == '/') {
path += 2;
}
if(handle_simple_path(pkg, path)) {
continue;
}
if(add_entry_to_files_list(&filelist, &files_size, mtree_entry, path) < 0) {
goto error;
}
}
if(ret != ARCHIVE_EOF && ret != ARCHIVE_OK) { /* An error occurred */
_alpm_log(handle, ALPM_LOG_DEBUG, _("error while reading mtree of package %s: %s\n"),
pkg->filename, archive_error_string(mtree));
GOTO_ERR(handle, ALPM_ERR_LIBARCHIVE, error);
}
/* throw away any files we loaded directly from the archive */
for(i = 0; i < pkg->files.count; i++) {
free(pkg->files.files[i].name);
}
free(pkg->files.files);
/* copy over new filelist */
memcpy(&pkg->files, &filelist, sizeof(alpm_filelist_t));
free(mtree_data);
_alpm_archive_read_free(mtree);
_alpm_log(handle, ALPM_LOG_DEBUG, "finished mtree reading for %s\n", pkg->filename);
return 0;
error:
/* throw away any files we loaded from the mtree */
for(i = 0; i < filelist.count; i++) {
free(filelist.files[i].name);
}
free(filelist.files);
free(mtree_data);
_alpm_archive_read_free(mtree);
return -1;
}
/**
* Load a package and create the corresponding alpm_pkg_t struct.
* @param handle the context handle
* @param pkgfile path to the package file
* @param full whether to stop the load after metadata is read or continue
* through the full archive
*/
alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle,
const char *pkgfile, int full)
{
int ret, fd;
int config = 0;
int hit_mtree = 0;
struct archive *archive;
struct archive_entry *entry;
alpm_pkg_t *newpkg;
struct stat st;
size_t files_size = 0;
if(pkgfile == NULL || strlen(pkgfile) == 0) {
RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL);
}
fd = _alpm_open_archive(handle, pkgfile, &st, &archive, ALPM_ERR_PKG_OPEN);
if(fd < 0) {
if(errno == ENOENT) {
handle->pm_errno = ALPM_ERR_PKG_NOT_FOUND;
} else if(errno == EACCES) {
handle->pm_errno = ALPM_ERR_BADPERMS;
} else {
handle->pm_errno = ALPM_ERR_PKG_OPEN;
}
return NULL;
}
newpkg = _alpm_pkg_new();
if(newpkg == NULL) {
GOTO_ERR(handle, ALPM_ERR_MEMORY, error);
}
STRDUP(newpkg->filename, pkgfile, GOTO_ERR(handle, ALPM_ERR_MEMORY, error));
newpkg->size = st.st_size;
_alpm_log(handle, ALPM_LOG_DEBUG, "starting package load for %s\n", pkgfile);
/* If full is false, only read through the archive until we find our needed
* metadata. If it is true, read through the entire archive, which serves
* as a verification of integrity and allows us to create the filelist. */
while((ret = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) {
const char *entry_name = archive_entry_pathname(entry);
if(strcmp(entry_name, ".PKGINFO") == 0) {
/* parse the info file */
if(parse_descfile(handle, archive, newpkg) != 0) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not parse package description file in %s\n"),
pkgfile);
goto pkg_invalid;
}
if(newpkg->name == NULL || strlen(newpkg->name) == 0) {
_alpm_log(handle, ALPM_LOG_ERROR, _("missing package name in %s\n"), pkgfile);
goto pkg_invalid;
}
if(newpkg->version == NULL || strlen(newpkg->version) == 0) {
_alpm_log(handle, ALPM_LOG_ERROR, _("missing package version in %s\n"), pkgfile);
goto pkg_invalid;
}
if(strchr(newpkg->version, '-') == NULL) {
_alpm_log(handle, ALPM_LOG_ERROR, _("invalid package version in %s\n"), pkgfile);
goto pkg_invalid;
}
config = 1;
continue;
} else if(full && strcmp(entry_name, ".MTREE") == 0) {
/* building the file list: cheap way
* get the filelist from the mtree file rather than scanning
* the whole archive */
hit_mtree = build_filelist_from_mtree(handle, newpkg, archive) == 0;
continue;
} else if(handle_simple_path(newpkg, entry_name)) {
continue;
} else if(full && !hit_mtree) {
/* building the file list: expensive way */
if(add_entry_to_files_list(&newpkg->files, &files_size, entry, entry_name) < 0) {
goto error;
}
}
if(archive_read_data_skip(archive)) {
_alpm_log(handle, ALPM_LOG_ERROR, _("error while reading package %s: %s\n"),
pkgfile, archive_error_string(archive));
GOTO_ERR(handle, ALPM_ERR_LIBARCHIVE, error);
}
/* if we are not doing a full read, see if we have all we need */
if((!full || hit_mtree) && config) {
break;
}
}
if(ret != ARCHIVE_EOF && ret != ARCHIVE_OK) { /* An error occurred */
_alpm_log(handle, ALPM_LOG_ERROR, _("error while reading package %s: %s\n"),
pkgfile, archive_error_string(archive));
GOTO_ERR(handle, ALPM_ERR_LIBARCHIVE, error);
}
if(!config) {
_alpm_log(handle, ALPM_LOG_ERROR, _("missing package metadata in %s\n"), pkgfile);
goto pkg_invalid;
}
/* internal fields for package struct */
newpkg->origin = ALPM_PKG_FROM_FILE;
STRDUP(newpkg->origin_data.file, pkgfile, goto error);
newpkg->ops = get_file_pkg_ops();
newpkg->handle = handle;
newpkg->infolevel = INFRQ_BASE | INFRQ_DESC | INFRQ_SCRIPTLET;
newpkg->validation = ALPM_PKG_VALIDATION_NONE;
if(full) {
if(newpkg->files.files) {
/* attempt to hand back any memory we don't need */
REALLOC(newpkg->files.files, sizeof(alpm_file_t) * newpkg->files.count, (void)0);
/* "checking for conflicts" requires a sorted list, ensure that here */
_alpm_log(handle, ALPM_LOG_DEBUG,
"sorting package filelist for %s\n", pkgfile);
_alpm_filelist_sort(&newpkg->files);
}
newpkg->infolevel |= INFRQ_FILES;
}
if(_alpm_pkg_check_meta(newpkg) != 0) {
goto pkg_invalid;
}
_alpm_archive_read_free(archive);
close(fd);
return newpkg;
pkg_invalid:
handle->pm_errno = ALPM_ERR_PKG_INVALID;
error:
_alpm_pkg_free(newpkg);
_alpm_archive_read_free(archive);
close(fd);
return NULL;
}
/* adopted limit from repo-add */
#define MAX_SIGFILE_SIZE 16384
static int read_sigfile(const char *sigpath, unsigned char **sig)
{
struct stat st;
FILE *fp;
if((fp = fopen(sigpath, "rb")) == NULL) {
return -1;
}
if(fstat(fileno(fp), &st) != 0 || st.st_size > MAX_SIGFILE_SIZE) {
fclose(fp);
return -1;
}
MALLOC(*sig, st.st_size, fclose(fp); return -1);
if(fread(*sig, st.st_size, 1, fp) != 1) {
free(*sig);
fclose(fp);
return -1;
}
fclose(fp);
return st.st_size;
}
int SYMEXPORT alpm_pkg_load(alpm_handle_t *handle, const char *filename, int full,
int level, alpm_pkg_t **pkg)
{
int validation = 0;
char *sigpath;
alpm_pkg_t *pkg_temp;
CHECK_HANDLE(handle, return -1);
ASSERT(pkg != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
sigpath = _alpm_sigpath(handle, filename);
if(sigpath && !_alpm_access(handle, NULL, sigpath, R_OK)) {
if(level & ALPM_SIG_PACKAGE) {
alpm_list_t *keys = NULL;
int fail = 0;
unsigned char *sig = NULL;
int len = read_sigfile(sigpath, &sig);
if(len == -1) {
_alpm_log(handle, ALPM_LOG_ERROR,
_("failed to read signature file: %s\n"), sigpath);
free(sigpath);
return -1;
}
if(alpm_extract_keyid(handle, filename, sig, len, &keys) == 0) {
alpm_list_t *k;
for(k = keys; k; k = k->next) {
char *key = k->data;
if(_alpm_key_in_keychain(handle, key) == 0) {
pkg_temp = _alpm_pkg_load_internal(handle, filename, full);
if(_alpm_key_import(handle, NULL, key) == -1) {
fail = 1;
}
_alpm_pkg_free(pkg_temp);
}
}
FREELIST(keys);
}
free(sig);
if(fail) {
_alpm_log(handle, ALPM_LOG_ERROR, _("required key missing from keyring\n"));
free(sigpath);
return -1;
}
}
}
free(sigpath);
if(_alpm_pkg_validate_internal(handle, filename, NULL, level, NULL,
&validation) == -1) {
/* pm_errno is set by pkg_validate */
return -1;
}
*pkg = _alpm_pkg_load_internal(handle, filename, full);
if(*pkg == NULL) {
/* pm_errno is set by pkg_load */
return -1;
}
(*pkg)->validation = validation;
return 0;
}

View file

@ -1,764 +0,0 @@
/*
* be_sync.c : backend for sync databases
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 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, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <unistd.h>
/* libarchive */
#include <archive.h>
#include <archive_entry.h>
/* libalpm */
#include "util.h"
#include "log.h"
#include "libarchive-compat.h"
#include "alpm.h"
#include "alpm_list.h"
#include "package.h"
#include "handle.h"
#include "deps.h"
#include "dload.h"
#include "filelist.h"
static char *get_sync_dir(alpm_handle_t *handle)
{
size_t len = strlen(handle->dbpath) + 6;
char *syncpath;
struct stat buf;
MALLOC(syncpath, len, RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
snprintf(syncpath, len, "%s%s", handle->dbpath, "sync/");
if(stat(syncpath, &buf) != 0) {
_alpm_log(handle, ALPM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
syncpath);
if(_alpm_makepath(syncpath) != 0) {
free(syncpath);
RET_ERR(handle, ALPM_ERR_SYSTEM, NULL);
}
} else if(!S_ISDIR(buf.st_mode)) {
_alpm_log(handle, ALPM_LOG_WARNING, _("removing invalid file: %s\n"), syncpath);
if(unlink(syncpath) != 0 || _alpm_makepath(syncpath) != 0) {
free(syncpath);
RET_ERR(handle, ALPM_ERR_SYSTEM, NULL);
}
}
return syncpath;
}
static int sync_db_validate(alpm_db_t *db)
{
int siglevel;
const char *dbpath;
if(db->status & DB_STATUS_VALID || db->status & DB_STATUS_MISSING) {
return 0;
}
if(db->status & DB_STATUS_INVALID) {
db->handle->pm_errno = ALPM_ERR_DB_INVALID_SIG;
return -1;
}
dbpath = _alpm_db_path(db);
if(!dbpath) {
/* pm_errno set in _alpm_db_path() */
return -1;
}
/* we can skip any validation if the database doesn't exist */
if(_alpm_access(db->handle, NULL, dbpath, R_OK) != 0 && errno == ENOENT) {
alpm_event_database_missing_t event = {
.type = ALPM_EVENT_DATABASE_MISSING,
.dbname = db->treename
};
db->status &= ~DB_STATUS_EXISTS;
db->status |= DB_STATUS_MISSING;
EVENT(db->handle, &event);
goto valid;
}
db->status |= DB_STATUS_EXISTS;
db->status &= ~DB_STATUS_MISSING;
/* this takes into account the default verification level if UNKNOWN
* was assigned to this db */
siglevel = alpm_db_get_siglevel(db);
if(siglevel & ALPM_SIG_DATABASE) {
int retry, ret;
do {
retry = 0;
alpm_siglist_t *siglist;
ret = _alpm_check_pgp_helper(db->handle, dbpath, NULL,
siglevel & ALPM_SIG_DATABASE_OPTIONAL, siglevel & ALPM_SIG_DATABASE_MARGINAL_OK,
siglevel & ALPM_SIG_DATABASE_UNKNOWN_OK, &siglist);
if(ret) {
retry = _alpm_process_siglist(db->handle, db->treename, siglist,
siglevel & ALPM_SIG_DATABASE_OPTIONAL, siglevel & ALPM_SIG_DATABASE_MARGINAL_OK,
siglevel & ALPM_SIG_DATABASE_UNKNOWN_OK);
}
alpm_siglist_cleanup(siglist);
free(siglist);
} while(retry);
if(ret) {
db->status &= ~DB_STATUS_VALID;
db->status |= DB_STATUS_INVALID;
db->handle->pm_errno = ALPM_ERR_DB_INVALID_SIG;
return 1;
}
}
valid:
db->status |= DB_STATUS_VALID;
db->status &= ~DB_STATUS_INVALID;
return 0;
}
int SYMEXPORT alpm_db_update(alpm_handle_t *handle, alpm_list_t *dbs, int force) {
char *syncpath;
char *temporary_syncpath;
const char *dbext = handle->dbext;
alpm_list_t *i;
int ret = -1;
mode_t oldmask;
alpm_list_t *payloads = NULL;
alpm_event_t event;
/* Sanity checks */
CHECK_HANDLE(handle, return -1);
ASSERT(dbs != NULL, return -1);
handle->pm_errno = ALPM_ERR_OK;
syncpath = get_sync_dir(handle);
ASSERT(syncpath != NULL, return -1);
temporary_syncpath = _alpm_temporary_download_dir_setup(syncpath, handle->sandboxuser);
ASSERT(temporary_syncpath != NULL, FREE(syncpath); return -1);
/* make sure we have a sane umask */
oldmask = umask(0022);
/* attempt to grab a lock */
if(_alpm_handle_lock(handle)) {
GOTO_ERR(handle, ALPM_ERR_HANDLE_LOCK, cleanup);
}
for(i = dbs; i; i = i->next) {
alpm_db_t *db = i->data;
int dbforce = force;
struct dload_payload *payload = NULL;
size_t len;
int siglevel;
if(!(db->usage & ALPM_DB_USAGE_SYNC)) {
continue;
}
ASSERT(db != handle->db_local, GOTO_ERR(handle, ALPM_ERR_WRONG_ARGS, cleanup));
ASSERT(db->servers != NULL, GOTO_ERR(handle, ALPM_ERR_SERVER_NONE, cleanup));
/* force update of invalid databases to fix potential mismatched database/signature */
if(db->status & DB_STATUS_INVALID) {
dbforce = 1;
}
siglevel = alpm_db_get_siglevel(db);
CALLOC(payload, 1, sizeof(*payload), GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
payload->servers = db->servers;
/* print server + filename into a buffer */
len = strlen(db->treename) + strlen(dbext) + 1;
MALLOC(payload->filepath, len,
FREE(payload); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
snprintf(payload->filepath, len, "%s%s", db->treename, dbext);
STRDUP(payload->remote_name, payload->filepath,
_alpm_dload_payload_reset(payload); FREE(payload);
GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
payload->destfile_name = _alpm_get_fullpath(temporary_syncpath, payload->remote_name, "");
payload->tempfile_name = _alpm_get_fullpath(temporary_syncpath, payload->remote_name, ".part");
if(!payload->destfile_name || !payload->tempfile_name) {
_alpm_dload_payload_reset(payload);
FREE(payload);
GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup);
}
payload->handle = handle;
payload->force = dbforce;
payload->unlink_on_fail = 1;
payload->download_signature = (siglevel & ALPM_SIG_DATABASE);
payload->signature_optional = (siglevel & ALPM_SIG_DATABASE_OPTIONAL);
/* set hard upper limit of 128 MiB */
payload->max_size = 128 * 1024 * 1024;
payloads = alpm_list_add(payloads, payload);
}
if(payloads == NULL) {
ret = 0;
goto cleanup;
}
event.type = ALPM_EVENT_DB_RETRIEVE_START;
EVENT(handle, &event);
ret = _alpm_download(handle, payloads, syncpath, temporary_syncpath);
if(ret < 0) {
event.type = ALPM_EVENT_DB_RETRIEVE_FAILED;
EVENT(handle, &event);
goto cleanup;
}
event.type = ALPM_EVENT_DB_RETRIEVE_DONE;
EVENT(handle, &event);
for(i = dbs; i; i = i->next) {
alpm_db_t *db = i->data;
if(!(db->usage & ALPM_DB_USAGE_SYNC)) {
continue;
}
/* Cache needs to be rebuilt */
_alpm_db_free_pkgcache(db);
/* clear all status flags regarding validity/existence */
db->status &= ~DB_STATUS_VALID;
db->status &= ~DB_STATUS_INVALID;
db->status &= ~DB_STATUS_EXISTS;
db->status &= ~DB_STATUS_MISSING;
/* if the download failed skip validation to preserve the download error */
if(sync_db_validate(db) != 0) {
_alpm_log(handle, ALPM_LOG_DEBUG, "failed to validate db: %s\n",
db->treename);
/* pm_errno should be set */
ret = -1;
}
}
cleanup:
_alpm_handle_unlock(handle);
if(ret == -1) {
/* pm_errno was set by the download code */
_alpm_log(handle, ALPM_LOG_DEBUG, "failed to sync dbs: %s\n",
alpm_strerror(handle->pm_errno));
} else {
handle->pm_errno = ALPM_ERR_OK;
}
if(payloads) {
alpm_list_free_inner(payloads, (alpm_list_fn_free)_alpm_dload_payload_reset);
FREELIST(payloads);
}
FREE(temporary_syncpath);
FREE(syncpath);
umask(oldmask);
return ret;
}
/* Forward decl so I don't reorganize the whole file right now */
static int sync_db_read(alpm_db_t *db, struct archive *archive,
struct archive_entry *entry, alpm_pkg_t **likely_pkg);
static int _sync_get_validation(alpm_pkg_t *pkg)
{
if(pkg->validation) {
return pkg->validation;
}
if(pkg->md5sum) {
pkg->validation |= ALPM_PKG_VALIDATION_MD5SUM;
}
if(pkg->sha256sum) {
pkg->validation |= ALPM_PKG_VALIDATION_SHA256SUM;
}
if(pkg->base64_sig) {
pkg->validation |= ALPM_PKG_VALIDATION_SIGNATURE;
}
if(!pkg->validation) {
pkg->validation |= ALPM_PKG_VALIDATION_NONE;
}
return pkg->validation;
}
/** Package sync operations struct accessor. We implement this as a method
* because we want to reuse the majority of the default_pkg_ops struct and
* add only a few operations of our own on top.
*/
static const struct pkg_operations *get_sync_pkg_ops(void)
{
static struct pkg_operations sync_pkg_ops;
static int sync_pkg_ops_initialized = 0;
if(!sync_pkg_ops_initialized) {
sync_pkg_ops = default_pkg_ops;
sync_pkg_ops.get_validation = _sync_get_validation;
sync_pkg_ops_initialized = 1;
}
return &sync_pkg_ops;
}
static alpm_pkg_t *load_pkg_for_entry(alpm_db_t *db, const char *entryname,
const char **entry_filename, alpm_pkg_t *likely_pkg)
{
char *pkgname = NULL, *pkgver = NULL;
unsigned long pkgname_hash;
alpm_pkg_t *pkg;
/* get package and db file names */
if(entry_filename) {
char *fname = strrchr(entryname, '/');
if(fname) {
*entry_filename = fname + 1;
} else {
*entry_filename = NULL;
}
}
if(_alpm_splitname(entryname, &pkgname, &pkgver, &pkgname_hash) != 0) {
_alpm_log(db->handle, ALPM_LOG_ERROR,
_("invalid name for database entry '%s'\n"), entryname);
return NULL;
}
if(likely_pkg && pkgname_hash == likely_pkg->name_hash
&& strcmp(likely_pkg->name, pkgname) == 0) {
pkg = likely_pkg;
} else {
pkg = _alpm_pkghash_find(db->pkgcache, pkgname);
}
if(pkg == NULL) {
pkg = _alpm_pkg_new();
if(pkg == NULL) {
RET_ERR(db->handle, ALPM_ERR_MEMORY, NULL);
}
pkg->name = pkgname;
pkg->version = pkgver;
pkg->name_hash = pkgname_hash;
pkg->origin = ALPM_PKG_FROM_SYNCDB;
pkg->origin_data.db = db;
pkg->ops = get_sync_pkg_ops();
pkg->handle = db->handle;
if(_alpm_pkg_check_meta(pkg) != 0) {
_alpm_pkg_free(pkg);
RET_ERR(db->handle, ALPM_ERR_PKG_INVALID, NULL);
}
/* add to the collection */
_alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
pkg->name, db->treename);
if(_alpm_pkghash_add(&db->pkgcache, pkg) == NULL) {
_alpm_pkg_free(pkg);
RET_ERR(db->handle, ALPM_ERR_MEMORY, NULL);
}
} else {
free(pkgname);
free(pkgver);
}
return pkg;
}
/* This function doesn't work as well as one might think, as size of database
* entries varies considerably. Adding signatures nearly doubles the size of a
* single entry. These current values are heavily influenced by Arch Linux;
* databases with a single signature per package. */
static size_t estimate_package_count(struct stat *st, struct archive *archive)
{
int per_package;
switch(_alpm_archive_filter_code(archive)) {
case ARCHIVE_COMPRESSION_NONE:
per_package = 3015;
break;
case ARCHIVE_COMPRESSION_GZIP:
case ARCHIVE_COMPRESSION_COMPRESS:
per_package = 464;
break;
case ARCHIVE_COMPRESSION_BZIP2:
per_package = 394;
break;
case ARCHIVE_COMPRESSION_LZMA:
case ARCHIVE_COMPRESSION_XZ:
per_package = 400;
break;
#ifdef ARCHIVE_COMPRESSION_UU
case ARCHIVE_COMPRESSION_UU:
per_package = 3015 * 4 / 3;
break;
#endif
default:
/* assume it is at least somewhat compressed */
per_package = 500;
}
return (size_t)((st->st_size / per_package) + 1);
}
static int sync_db_populate(alpm_db_t *db)
{
const char *dbpath;
size_t est_count, count;
int fd;
int ret = 0;
int archive_ret;
struct stat buf;
struct archive *archive;
struct archive_entry *entry;
alpm_pkg_t *pkg = NULL;
if(db->status & DB_STATUS_INVALID) {
RET_ERR(db->handle, ALPM_ERR_DB_INVALID, -1);
}
if(db->status & DB_STATUS_MISSING) {
RET_ERR(db->handle, ALPM_ERR_DB_NOT_FOUND, -1);
}
dbpath = _alpm_db_path(db);
if(!dbpath) {
/* pm_errno set in _alpm_db_path() */
return -1;
}
fd = _alpm_open_archive(db->handle, dbpath, &buf,
&archive, ALPM_ERR_DB_OPEN);
if(fd < 0) {
db->status &= ~DB_STATUS_VALID;
db->status |= DB_STATUS_INVALID;
return -1;
}
est_count = estimate_package_count(&buf, archive);
/* currently only .files dbs contain file lists - make flexible when required*/
if(strcmp(db->handle->dbext, ".files") == 0) {
/* files databases are about four times larger on average */
est_count /= 4;
}
db->pkgcache = _alpm_pkghash_create(est_count);
if(db->pkgcache == NULL) {
ret = -1;
GOTO_ERR(db->handle, ALPM_ERR_MEMORY, cleanup);
}
while((archive_ret = archive_read_next_header(archive, &entry)) == ARCHIVE_OK) {
mode_t mode = archive_entry_mode(entry);
if(!S_ISDIR(mode)) {
/* we have desc or depends - parse it */
if(sync_db_read(db, archive, entry, &pkg) != 0) {
_alpm_log(db->handle, ALPM_LOG_ERROR,
_("could not parse package description file '%s' from db '%s'\n"),
archive_entry_pathname(entry), db->treename);
ret = -1;
}
}
}
/* the db file was successfully read, but contained errors */
if(ret == -1) {
db->status &= ~DB_STATUS_VALID;
db->status |= DB_STATUS_INVALID;
_alpm_db_free_pkgcache(db);
GOTO_ERR(db->handle, ALPM_ERR_DB_INVALID, cleanup);
}
/* reading the db file failed */
if(archive_ret != ARCHIVE_EOF) {
_alpm_log(db->handle, ALPM_LOG_ERROR, _("could not read db '%s' (%s)\n"),
db->treename, archive_error_string(archive));
_alpm_db_free_pkgcache(db);
ret = -1;
GOTO_ERR(db->handle, ALPM_ERR_LIBARCHIVE, cleanup);
}
count = alpm_list_count(db->pkgcache->list);
if(count > 0) {
db->pkgcache->list = alpm_list_msort(db->pkgcache->list,
count, _alpm_pkg_cmp);
}
_alpm_log(db->handle, ALPM_LOG_DEBUG,
"added %zu packages to package cache for db '%s'\n",
count, db->treename);
cleanup:
_alpm_archive_read_free(archive);
if(fd >= 0) {
close(fd);
}
return ret;
}
/* This function validates %FILENAME%. filename must be between 3 and
* PATH_MAX characters and cannot be contain a path */
static int _alpm_validate_filename(alpm_db_t *db, const char *pkgname,
const char *filename)
{
size_t len = strlen(filename);
if(filename[0] == '.') {
errno = EINVAL;
_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: filename "
"of package %s is illegal\n"), db->treename, pkgname);
return -1;
} else if(memchr(filename, '/', len) != NULL) {
errno = EINVAL;
_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: filename "
"of package %s is illegal\n"), db->treename, pkgname);
return -1;
} else if(len > PATH_MAX) {
errno = EINVAL;
_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: filename "
"of package %s is too long\n"), db->treename, pkgname);
return -1;
}
return 0;
}
#define READ_NEXT() do { \
if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \
line = buf.line; \
_alpm_strip_newline(line, buf.real_line_size); \
} while(0)
#define READ_AND_STORE(f) do { \
READ_NEXT(); \
STRDUP(f, line, goto error); \
} while(0)
#define READ_AND_STORE_ALL(f) do { \
char *linedup; \
if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \
if(_alpm_strip_newline(buf.line, buf.real_line_size) == 0) break; \
STRDUP(linedup, buf.line, goto error); \
f = alpm_list_add(f, linedup); \
} while(1) /* note the while(1) and not (0) */
#define READ_AND_SPLITDEP(f) do { \
if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) goto error; \
if(_alpm_strip_newline(buf.line, buf.real_line_size) == 0) break; \
f = alpm_list_add(f, alpm_dep_from_string(line)); \
} while(1) /* note the while(1) and not (0) */
static int sync_db_read(alpm_db_t *db, struct archive *archive,
struct archive_entry *entry, alpm_pkg_t **likely_pkg)
{
const char *entryname, *filename;
alpm_pkg_t *pkg;
struct archive_read_buffer buf = {0};
entryname = archive_entry_pathname(entry);
if(entryname == NULL) {
_alpm_log(db->handle, ALPM_LOG_DEBUG,
"invalid archive entry provided to _alpm_sync_db_read, skipping\n");
return -1;
}
_alpm_log(db->handle, ALPM_LOG_FUNCTION, "loading package data from archive entry %s\n",
entryname);
/* 512K for a line length seems reasonable */
buf.max_line_size = 512 * 1024;
pkg = load_pkg_for_entry(db, entryname, &filename, *likely_pkg);
if(pkg == NULL) {
_alpm_log(db->handle, ALPM_LOG_DEBUG,
"entry %s could not be loaded into %s sync database\n",
entryname, db->treename);
return -1;
}
if(filename == NULL) {
/* A file exists outside of a subdirectory. This isn't a read error, so return
* success and try to continue on. */
_alpm_log(db->handle, ALPM_LOG_WARNING, _("unknown database file: %s\n"),
entryname);
return 0;
}
if(strcmp(filename, "desc") == 0 || strcmp(filename, "depends") == 0
|| strcmp(filename, "files") == 0) {
int ret;
while((ret = _alpm_archive_fgets(archive, &buf)) == ARCHIVE_OK) {
char *line = buf.line;
if(_alpm_strip_newline(line, buf.real_line_size) == 0) {
/* length of stripped line was zero */
continue;
}
if(strcmp(line, "%NAME%") == 0) {
READ_NEXT();
if(strcmp(line, pkg->name) != 0) {
_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: name "
"mismatch on package %s\n"), db->treename, pkg->name);
}
} else if(strcmp(line, "%VERSION%") == 0) {
READ_NEXT();
if(strcmp(line, pkg->version) != 0) {
_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s database is inconsistent: version "
"mismatch on package %s\n"), db->treename, pkg->name);
}
} else if(strcmp(line, "%FILENAME%") == 0) {
READ_AND_STORE(pkg->filename);
if(_alpm_validate_filename(db, pkg->name, pkg->filename) < 0) {
return -1;
}
} else if(strcmp(line, "%BASE%") == 0) {
READ_AND_STORE(pkg->base);
} else if(strcmp(line, "%DESC%") == 0) {
READ_AND_STORE(pkg->desc);
} else if(strcmp(line, "%GROUPS%") == 0) {
READ_AND_STORE_ALL(pkg->groups);
} else if(strcmp(line, "%URL%") == 0) {
READ_AND_STORE(pkg->url);
} else if(strcmp(line, "%LICENSE%") == 0) {
READ_AND_STORE_ALL(pkg->licenses);
} else if(strcmp(line, "%ARCH%") == 0) {
READ_AND_STORE(pkg->arch);
} else if(strcmp(line, "%BUILDDATE%") == 0) {
READ_NEXT();
pkg->builddate = _alpm_parsedate(line);
} else if(strcmp(line, "%PACKAGER%") == 0) {
READ_AND_STORE(pkg->packager);
} else if(strcmp(line, "%CSIZE%") == 0) {
READ_NEXT();
pkg->size = _alpm_strtoofft(line);
} else if(strcmp(line, "%ISIZE%") == 0) {
READ_NEXT();
pkg->isize = _alpm_strtoofft(line);
} else if(strcmp(line, "%MD5SUM%") == 0) {
READ_AND_STORE(pkg->md5sum);
} else if(strcmp(line, "%SHA256SUM%") == 0) {
READ_AND_STORE(pkg->sha256sum);
} else if(strcmp(line, "%PGPSIG%") == 0) {
READ_AND_STORE(pkg->base64_sig);
} else if(strcmp(line, "%REPLACES%") == 0) {
READ_AND_SPLITDEP(pkg->replaces);
} else if(strcmp(line, "%DEPENDS%") == 0) {
READ_AND_SPLITDEP(pkg->depends);
} else if(strcmp(line, "%OPTDEPENDS%") == 0) {
READ_AND_SPLITDEP(pkg->optdepends);
} else if(strcmp(line, "%MAKEDEPENDS%") == 0) {
READ_AND_SPLITDEP(pkg->makedepends);
} else if(strcmp(line, "%CHECKDEPENDS%") == 0) {
READ_AND_SPLITDEP(pkg->checkdepends);
} else if(strcmp(line, "%CONFLICTS%") == 0) {
READ_AND_SPLITDEP(pkg->conflicts);
} else if(strcmp(line, "%PROVIDES%") == 0) {
READ_AND_SPLITDEP(pkg->provides);
} else if(strcmp(line, "%FILES%") == 0) {
/* TODO: this could lazy load if there is future demand */
size_t files_count = 0, files_size = 0;
alpm_file_t *files = NULL;
while(1) {
if(_alpm_archive_fgets(archive, &buf) != ARCHIVE_OK) {
goto error;
}
line = buf.line;
if(_alpm_strip_newline(line, buf.real_line_size) == 0) {
break;
}
if(!_alpm_greedy_grow((void **)&files, &files_size,
(files_count ? (files_count + 1) * sizeof(alpm_file_t) : 8 * sizeof(alpm_file_t)))) {
goto error;
}
STRDUP(files[files_count].name, line, goto error);
files_count++;
}
/* attempt to hand back any memory we don't need */
if(files_count > 0) {
REALLOC(files, sizeof(alpm_file_t) * files_count, (void)0);
} else {
FREE(files);
}
pkg->files.count = files_count;
pkg->files.files = files;
_alpm_filelist_sort(&pkg->files);
} else if(strcmp(line, "%DATA%") == 0) {
alpm_list_t *i, *lines = NULL;
READ_AND_STORE_ALL(lines);
for(i = lines; i; i = i->next) {
alpm_pkg_xdata_t *pd = _alpm_pkg_parse_xdata(i->data);
if(pd == NULL || !alpm_list_append(&pkg->xdata, pd)) {
_alpm_pkg_xdata_free(pd);
FREELIST(lines);
goto error;
}
}
FREELIST(lines);
} else {
_alpm_log(db->handle, ALPM_LOG_WARNING, _("%s: unknown key '%s' in sync database\n"), pkg->name, line);
alpm_list_t *lines = NULL;
READ_AND_STORE_ALL(lines);
FREELIST(lines);
}
}
if(ret != ARCHIVE_EOF) {
goto error;
}
*likely_pkg = pkg;
} else {
/* unknown database file */
_alpm_log(db->handle, ALPM_LOG_DEBUG, "unknown database file: %s\n", filename);
}
return 0;
error:
_alpm_log(db->handle, ALPM_LOG_DEBUG, "error parsing database file: %s\n", filename);
return -1;
}
struct db_operations sync_db_ops = {
.validate = sync_db_validate,
.populate = sync_db_populate,
.unregister = _alpm_db_unregister,
};
alpm_db_t *_alpm_db_register_sync(alpm_handle_t *handle, const char *treename,
int level)
{
alpm_db_t *db;
_alpm_log(handle, ALPM_LOG_DEBUG, "registering sync database '%s'\n", treename);
#ifndef HAVE_LIBGPGME
if(level != 0 && level != ALPM_SIG_USE_DEFAULT) {
RET_ERR(handle, ALPM_ERR_MISSING_CAPABILITY_SIGNATURES, NULL);
}
#endif
db = _alpm_db_new(treename, 0);
if(db == NULL) {
RET_ERR(handle, ALPM_ERR_DB_CREATE, NULL);
}
db->ops = &sync_db_ops;
db->handle = handle;
db->siglevel = level;
sync_db_validate(db);
handle->dbs_sync = alpm_list_add(handle->dbs_sync, db);
return db;
}

View file

@ -1,686 +0,0 @@
/*
* conflict.c
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2006 by David Kimpe <dnaku@frugalware.org>
* Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.org>
* Copyright (c) 2006 by Christian Hamar <krics@linuxforum.hu>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <sys/stat.h>
#include <dirent.h>
/* libalpm */
#include "conflict.h"
#include "alpm_list.h"
#include "alpm.h"
#include "handle.h"
#include "trans.h"
#include "util.h"
#include "log.h"
#include "deps.h"
#include "filelist.h"
/**
* @brief Creates a new conflict.
*/
static alpm_conflict_t *conflict_new(alpm_pkg_t *pkg1, alpm_pkg_t *pkg2,
alpm_depend_t *reason)
{
alpm_conflict_t *conflict;
CALLOC(conflict, 1, sizeof(alpm_conflict_t), return NULL);
ASSERT(_alpm_pkg_dup(pkg1, &conflict->package1) == 0, goto error);
ASSERT(_alpm_pkg_dup(pkg2, &conflict->package2) == 0, goto error);
conflict->reason = reason;
return conflict;
error:
alpm_conflict_free(conflict);
return NULL;
}
void SYMEXPORT alpm_conflict_free(alpm_conflict_t *conflict)
{
ASSERT(conflict != NULL, return);
_alpm_pkg_free(conflict->package1);
_alpm_pkg_free(conflict->package2);
FREE(conflict);
}
/**
* @brief Creates a copy of a conflict.
*/
alpm_conflict_t *_alpm_conflict_dup(const alpm_conflict_t *conflict)
{
alpm_conflict_t *newconflict;
CALLOC(newconflict, 1, sizeof(alpm_conflict_t), return NULL);
ASSERT(_alpm_pkg_dup(conflict->package1, &newconflict->package1) == 0, goto error);
ASSERT(_alpm_pkg_dup(conflict->package2, &newconflict->package2) == 0, goto error);
newconflict->reason = conflict->reason;
return newconflict;
error:
alpm_conflict_free(newconflict);
return NULL;
}
/**
* @brief Searches for a conflict in a list.
*
* @param needle conflict to search for
* @param haystack list of conflicts to search
*
* @return 1 if needle is in haystack, 0 otherwise
*/
static int conflict_isin(alpm_conflict_t *needle, alpm_list_t *haystack)
{
alpm_list_t *i;
for(i = haystack; i; i = i->next) {
alpm_conflict_t *conflict = i->data;
if(needle->package1->name_hash == conflict->package1->name_hash
&& needle->package2->name_hash == conflict->package2->name_hash
&& strcmp(needle->package1->name, conflict->package1->name) == 0
&& strcmp(needle->package2->name, conflict->package2->name) == 0) {
return 1;
}
}
return 0;
}
/**
* @brief Adds the pkg1/pkg2 conflict to the baddeps list.
*
* @param handle the context handle
* @param baddeps list to add conflict to
* @param pkg1 first package
* @param pkg2 package causing conflict
* @param reason reason for this conflict
*
* @return 0 on success, -1 on error
*/
static int add_conflict(alpm_handle_t *handle, alpm_list_t **baddeps,
alpm_pkg_t *pkg1, alpm_pkg_t *pkg2, alpm_depend_t *reason)
{
alpm_conflict_t *conflict = conflict_new(pkg1, pkg2, reason);
if(!conflict) {
return -1;
}
if(!conflict_isin(conflict, *baddeps)) {
char *conflict_str = alpm_dep_compute_string(reason);
*baddeps = alpm_list_add(*baddeps, conflict);
_alpm_log(handle, ALPM_LOG_DEBUG, "package %s conflicts with %s (by %s)\n",
pkg1->name, pkg2->name, conflict_str);
free(conflict_str);
} else {
alpm_conflict_free(conflict);
}
return 0;
}
/**
* @brief Check if packages from list1 conflict with packages from list2.
*
* @details This looks at the conflicts fields of all packages from list1, and
* sees if they match packages from list2. If a conflict (pkg1, pkg2) is found,
* it is added to the baddeps list in this order if order >= 0, or reverse
* order (pkg2,pkg1) otherwise.
*
* @param handle the context handle
* @param list1 first list of packages
* @param list2 second list of packages
* @param baddeps list to store conflicts
* @param order if >= 0 the conflict order is preserved, if < 0 it's reversed
*/
static void check_conflict(alpm_handle_t *handle,
alpm_list_t *list1, alpm_list_t *list2,
alpm_list_t **baddeps, int order)
{
alpm_list_t *i;
if(!baddeps) {
return;
}
for(i = list1; i; i = i->next) {
alpm_pkg_t *pkg1 = i->data;
alpm_list_t *j;
for(j = alpm_pkg_get_conflicts(pkg1); j; j = j->next) {
alpm_depend_t *conflict = j->data;
alpm_list_t *k;
for(k = list2; k; k = k->next) {
alpm_pkg_t *pkg2 = k->data;
if(pkg1->name_hash == pkg2->name_hash
&& strcmp(pkg1->name, pkg2->name) == 0) {
/* skip the package we're currently processing */
continue;
}
if(_alpm_depcmp(pkg2, conflict)) {
if(order >= 0) {
add_conflict(handle, baddeps, pkg1, pkg2, conflict);
} else {
add_conflict(handle, baddeps, pkg2, pkg1, conflict);
}
}
}
}
}
}
/**
* @brief Check for inter-conflicts in a list of packages.
*
* @param handle the context handle
* @param packages list of packages to check
*
* @return list of conflicts
*/
alpm_list_t *_alpm_innerconflicts(alpm_handle_t *handle, alpm_list_t *packages)
{
alpm_list_t *baddeps = NULL;
_alpm_log(handle, ALPM_LOG_DEBUG, "check targets vs targets\n");
check_conflict(handle, packages, packages, &baddeps, 0);
return baddeps;
}
/**
* @brief Returns a list of conflicts between a db and a list of packages.
*/
alpm_list_t *_alpm_outerconflicts(alpm_db_t *db, alpm_list_t *packages)
{
alpm_list_t *baddeps = NULL;
if(db == NULL) {
return NULL;
}
alpm_list_t *dblist = alpm_list_diff(_alpm_db_get_pkgcache(db),
packages, _alpm_pkg_cmp);
/* two checks to be done here for conflicts */
_alpm_log(db->handle, ALPM_LOG_DEBUG, "check targets vs db\n");
check_conflict(db->handle, packages, dblist, &baddeps, 1);
_alpm_log(db->handle, ALPM_LOG_DEBUG, "check db vs targets\n");
check_conflict(db->handle, dblist, packages, &baddeps, -1);
alpm_list_free(dblist);
return baddeps;
}
alpm_list_t SYMEXPORT *alpm_checkconflicts(alpm_handle_t *handle,
alpm_list_t *pkglist)
{
CHECK_HANDLE(handle, return NULL);
return _alpm_innerconflicts(handle, pkglist);
}
/**
* @brief Creates and adds a file conflict to a conflict list.
*
* @param handle the context handle
* @param conflicts the list of conflicts to append to
* @param filestr the conflicting file path
* @param pkg1 package that wishes to install the file
* @param pkg2 package that currently owns the file, or NULL if unowned
*
* @return the updated conflict list
*/
static alpm_list_t *add_fileconflict(alpm_handle_t *handle,
alpm_list_t *conflicts, const char *filestr,
alpm_pkg_t *pkg1, alpm_pkg_t *pkg2)
{
alpm_fileconflict_t *conflict;
CALLOC(conflict, 1, sizeof(alpm_fileconflict_t), goto error);
STRDUP(conflict->target, pkg1->name, goto error);
STRDUP(conflict->file, filestr, goto error);
if(!pkg2) {
conflict->type = ALPM_FILECONFLICT_FILESYSTEM;
STRDUP(conflict->ctarget, "", goto error);
} else if(pkg2->origin == ALPM_PKG_FROM_LOCALDB) {
conflict->type = ALPM_FILECONFLICT_FILESYSTEM;
STRDUP(conflict->ctarget, pkg2->name, goto error);
} else {
conflict->type = ALPM_FILECONFLICT_TARGET;
STRDUP(conflict->ctarget, pkg2->name, goto error);
}
conflicts = alpm_list_add(conflicts, conflict);
_alpm_log(handle, ALPM_LOG_DEBUG, "found file conflict %s, packages %s and %s\n",
filestr, pkg1->name, pkg2 ? pkg2->name : "(filesystem)");
return conflicts;
error:
alpm_fileconflict_free(conflict);
RET_ERR(handle, ALPM_ERR_MEMORY, conflicts);
}
void SYMEXPORT alpm_fileconflict_free(alpm_fileconflict_t *conflict)
{
ASSERT(conflict != NULL, return);
FREE(conflict->ctarget);
FREE(conflict->file);
FREE(conflict->target);
FREE(conflict);
}
/**
* @brief Recursively checks if a set of packages own all subdirectories and
* files in a directory.
*
* @param handle the context handle
* @param dirpath path of the directory to check
* @param pkgs packages being checked against
*
* @return 1 if a package owns all subdirectories and files, 0 otherwise
*/
static int dir_belongsto_pkgs(alpm_handle_t *handle, const char *dirpath,
alpm_list_t *pkgs)
{
char path[PATH_MAX], full_path[PATH_MAX];
DIR *dir;
struct dirent *ent = NULL;
snprintf(full_path, PATH_MAX, "%s%s", handle->root, dirpath);
dir = opendir(full_path);
if(dir == NULL) {
return 0;
}
while((ent = readdir(dir)) != NULL) {
const char *name = ent->d_name;
int owned = 0, is_dir = 0;
alpm_list_t *i;
struct stat sbuf;
if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
continue;
}
snprintf(full_path, PATH_MAX, "%s%s%s", handle->root, dirpath, name);
if(lstat(full_path, &sbuf) != 0) {
_alpm_log(handle, ALPM_LOG_DEBUG, "could not stat %s\n", full_path);
closedir(dir);
return 0;
}
is_dir = S_ISDIR(sbuf.st_mode);
snprintf(path, PATH_MAX, "%s%s%s", dirpath, name, is_dir ? "/" : "");
for(i = pkgs; i && !owned; i = i->next) {
if(alpm_filelist_contains(alpm_pkg_get_files(i->data), path)) {
owned = 1;
}
}
if(owned && is_dir) {
owned = dir_belongsto_pkgs(handle, path, pkgs);
}
if(!owned) {
closedir(dir);
_alpm_log(handle, ALPM_LOG_DEBUG,
"unowned file %s found in directory\n", path);
return 0;
}
}
closedir(dir);
return 1;
}
static alpm_list_t *alpm_db_find_file_owners(alpm_db_t* db, const char *path)
{
alpm_list_t *i, *owners = NULL;
for(i = alpm_db_get_pkgcache(db); i; i = i->next) {
if(alpm_filelist_contains(alpm_pkg_get_files(i->data), path)) {
owners = alpm_list_add(owners, i->data);
}
}
return owners;
}
static alpm_pkg_t *_alpm_find_file_owner(alpm_handle_t *handle, const char *path)
{
alpm_list_t *i;
for(i = alpm_db_get_pkgcache(handle->db_local); i; i = i->next) {
if(alpm_filelist_contains(alpm_pkg_get_files(i->data), path)) {
return i->data;
}
}
return NULL;
}
static int _alpm_can_overwrite_file(alpm_handle_t *handle, const char *path, const char *rootedpath)
{
return _alpm_fnmatch_patterns(handle->overwrite_files, path) == 0
|| _alpm_fnmatch_patterns(handle->overwrite_files, rootedpath) == 0;
}
/**
* @brief Find file conflicts that may occur during the transaction.
*
* @details Performs two checks:
* 1. check every target against every target
* 2. check every target against the filesystem
*
* @param handle the context handle
* @param upgrade list of packages being installed
* @param rem list of packages being removed
*
* @return list of file conflicts
*/
alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle,
alpm_list_t *upgrade, alpm_list_t *rem)
{
alpm_list_t *i, *conflicts = NULL;
size_t numtargs = alpm_list_count(upgrade);
size_t current;
size_t rootlen;
if(!upgrade) {
return NULL;
}
rootlen = strlen(handle->root);
/* TODO this whole function needs a huge change, which hopefully will
* be possible with real transactions. Right now we only do half as much
* here as we do when we actually extract files in add.c with our 12
* different cases. */
for(current = 0, i = upgrade; i; i = i->next, current++) {
alpm_pkg_t *p1 = i->data;
alpm_list_t *j;
alpm_list_t *newfiles = NULL;
alpm_pkg_t *dbpkg;
int percent = (current * 100) / numtargs;
PROGRESS(handle, ALPM_PROGRESS_CONFLICTS_START, "", percent,
numtargs, current);
/* CHECK 1: check every target against every target */
_alpm_log(handle, ALPM_LOG_DEBUG, "searching for file conflicts: %s\n",
p1->name);
for(j = i->next; j; j = j->next) {
alpm_list_t *common_files;
alpm_pkg_t *p2 = j->data;
alpm_filelist_t *p1_files = alpm_pkg_get_files(p1);
alpm_filelist_t *p2_files = alpm_pkg_get_files(p2);
common_files = _alpm_filelist_intersection(p1_files, p2_files);
if(common_files) {
alpm_list_t *k;
char path[PATH_MAX];
for(k = common_files; k; k = k->next) {
char *filename = k->data;
snprintf(path, PATH_MAX, "%s%s", handle->root, filename);
/* can skip file-file conflicts when forced *
* checking presence in p2_files detects dir-file or file-dir
* conflicts as the path from p1 is returned */
if(_alpm_can_overwrite_file(handle, filename, path)
&& alpm_filelist_contains(p2_files, filename)) {
_alpm_log(handle, ALPM_LOG_DEBUG,
"%s exists in both '%s' and '%s'\n", filename,
p1->name, p2->name);
_alpm_log(handle, ALPM_LOG_DEBUG,
"file-file conflict being forced\n");
continue;
}
conflicts = add_fileconflict(handle, conflicts, path, p1, p2);
if(handle->pm_errno == ALPM_ERR_MEMORY) {
alpm_list_free_inner(conflicts,
(alpm_list_fn_free) alpm_conflict_free);
alpm_list_free(conflicts);
alpm_list_free(common_files);
return NULL;
}
}
alpm_list_free(common_files);
}
}
/* CHECK 2: check every target against the filesystem */
_alpm_log(handle, ALPM_LOG_DEBUG, "searching for filesystem conflicts: %s\n",
p1->name);
dbpkg = _alpm_db_get_pkgfromcache(handle->db_local, p1->name);
/* Do two different checks here. If the package is currently installed,
* then only check files that are new in the new package. If the package
* is not currently installed, then simply stat the whole filelist. Note
* that the former list needs to be freed while the latter list should NOT
* be freed. */
if(dbpkg) {
/* older ver of package currently installed */
newfiles = _alpm_filelist_difference(alpm_pkg_get_files(p1),
alpm_pkg_get_files(dbpkg));
} else {
/* no version of package currently installed */
alpm_filelist_t *fl = alpm_pkg_get_files(p1);
size_t filenum;
for(filenum = 0; filenum < fl->count; filenum++) {
newfiles = alpm_list_add(newfiles, fl->files[filenum].name);
}
}
for(j = newfiles; j; j = j->next) {
const char *filestr = j->data;
const char *relative_path;
alpm_list_t *k;
/* have we acted on this conflict? */
int resolved_conflict = 0;
struct stat lsbuf;
char path[PATH_MAX];
size_t pathlen;
int pfile_isdir;
pathlen = snprintf(path, PATH_MAX, "%s%s", handle->root, filestr);
relative_path = path + rootlen;
/* stat the file - if it exists, do some checks */
if(llstat(path, &lsbuf) != 0) {
continue;
}
_alpm_log(handle, ALPM_LOG_DEBUG, "checking possible conflict: %s\n", path);
pfile_isdir = path[pathlen - 1] == '/';
if(pfile_isdir) {
if(S_ISDIR(lsbuf.st_mode)) {
_alpm_log(handle, ALPM_LOG_DEBUG, "file is a directory, not a conflict\n");
continue;
}
/* if we made it to here, we want all subsequent path comparisons to
* not include the trailing slash. This allows things like file ->
* directory replacements. */
path[pathlen - 1] = '\0';
/* Check if the directory was a file in dbpkg */
if(alpm_filelist_contains(alpm_pkg_get_files(dbpkg), relative_path)) {
size_t fslen = strlen(filestr);
_alpm_log(handle, ALPM_LOG_DEBUG,
"replacing package file with a directory, not a conflict\n");
resolved_conflict = 1;
/* go ahead and skip any files inside filestr as they will
* necessarily be resolved by replacing the file with a dir
* NOTE: afterward, j will point to the last file inside filestr */
for( ; j->next; j = j->next) {
const char *filestr2 = j->next->data;
if(strncmp(filestr, filestr2, fslen) != 0) {
break;
}
}
}
}
/* Check remove list (will we remove the conflicting local file?) */
for(k = rem; k && !resolved_conflict; k = k->next) {
alpm_pkg_t *rempkg = k->data;
if(rempkg && alpm_filelist_contains(alpm_pkg_get_files(rempkg),
relative_path)) {
_alpm_log(handle, ALPM_LOG_DEBUG,
"local file will be removed, not a conflict\n");
resolved_conflict = 1;
if(pfile_isdir) {
/* go ahead and skip any files inside filestr as they will
* necessarily be resolved by replacing the file with a dir
* NOTE: afterward, j will point to the last file inside filestr */
size_t fslen = strlen(filestr);
for( ; j->next; j = j->next) {
const char *filestr2 = j->next->data;
if(strncmp(filestr, filestr2, fslen) != 0) {
break;
}
}
}
}
}
/* Look at all the targets to see if file has changed hands */
for(k = upgrade; k && !resolved_conflict; k = k->next) {
alpm_pkg_t *localp2, *p2 = k->data;
if(!p2 || p1 == p2) {
/* skip p1; both p1 and p2 come directly from the upgrade list
* so they can be compared directly */
continue;
}
localp2 = _alpm_db_get_pkgfromcache(handle->db_local, p2->name);
/* localp2->files will be removed (target conflicts are handled by CHECK 1) */
if(localp2 && alpm_filelist_contains(alpm_pkg_get_files(localp2), relative_path)) {
size_t fslen = strlen(filestr);
/* skip removal of file, but not add. this will prevent a second
* package from removing the file when it was already installed
* by its new owner (whether the file is in backup array or not */
handle->trans->skip_remove =
alpm_list_add(handle->trans->skip_remove, strdup(relative_path));
_alpm_log(handle, ALPM_LOG_DEBUG,
"file changed packages, adding to remove skiplist\n");
resolved_conflict = 1;
if(filestr[fslen - 1] == '/') {
/* replacing a file with a directory:
* go ahead and skip any files inside filestr as they will
* necessarily be resolved by replacing the file with a dir
* NOTE: afterward, j will point to the last file inside filestr */
for( ; j->next; j = j->next) {
const char *filestr2 = j->next->data;
if(strncmp(filestr, filestr2, fslen) != 0) {
break;
}
}
}
}
}
/* check if all files of the dir belong to the installed pkg */
if(!resolved_conflict && S_ISDIR(lsbuf.st_mode)) {
alpm_list_t *owners;
size_t dir_len = strlen(relative_path) + 2;
char *dir = malloc(dir_len);
snprintf(dir, dir_len, "%s/", relative_path);
owners = alpm_db_find_file_owners(handle->db_local, dir);
if(owners) {
alpm_list_t *pkgs = NULL, *diff;
if(dbpkg) {
pkgs = alpm_list_add(pkgs, dbpkg);
}
pkgs = alpm_list_join(pkgs, alpm_list_copy(rem));
if((diff = alpm_list_diff(owners, pkgs, _alpm_pkg_cmp))) {
/* dir is owned by files we aren't removing */
/* TODO: with better commit ordering, we may be able to check
* against upgrades as well */
alpm_list_free(diff);
} else {
_alpm_log(handle, ALPM_LOG_DEBUG,
"checking if all files in %s belong to removed packages\n",
dir);
resolved_conflict = dir_belongsto_pkgs(handle, dir, owners);
}
alpm_list_free(pkgs);
alpm_list_free(owners);
}
free(dir);
}
/* is the file unowned and in the backup list of the new package? */
if(!resolved_conflict && _alpm_needbackup(relative_path, p1)) {
alpm_list_t *local_pkgs = _alpm_db_get_pkgcache(handle->db_local);
int found = 0;
for(k = local_pkgs; k && !found; k = k->next) {
if(alpm_filelist_contains(alpm_pkg_get_files(k->data), relative_path)) {
found = 1;
}
}
if(!found) {
_alpm_log(handle, ALPM_LOG_DEBUG,
"file was unowned but in new backup list\n");
resolved_conflict = 1;
}
}
/* skip file-file conflicts when being forced */
if(!S_ISDIR(lsbuf.st_mode)
&& _alpm_can_overwrite_file(handle, filestr, path)) {
_alpm_log(handle, ALPM_LOG_DEBUG,
"conflict with file on filesystem being forced\n");
resolved_conflict = 1;
}
if(!resolved_conflict) {
conflicts = add_fileconflict(handle, conflicts, path, p1,
_alpm_find_file_owner(handle, relative_path));
if(handle->pm_errno == ALPM_ERR_MEMORY) {
alpm_list_free_inner(conflicts,
(alpm_list_fn_free) alpm_conflict_free);
alpm_list_free(conflicts);
alpm_list_free(newfiles);
return NULL;
}
}
}
alpm_list_free(newfiles);
}
PROGRESS(handle, ALPM_PROGRESS_CONFLICTS_START, "", 100,
numtargs, current);
return conflicts;
}

View file

@ -1,33 +0,0 @@
/*
* conflict.h
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef ALPM_CONFLICT_H
#define ALPM_CONFLICT_H
#include "alpm.h"
#include "db.h"
#include "package.h"
alpm_conflict_t *_alpm_conflict_dup(const alpm_conflict_t *conflict);
alpm_list_t *_alpm_innerconflicts(alpm_handle_t *handle, alpm_list_t *packages);
alpm_list_t *_alpm_outerconflicts(alpm_db_t *db, alpm_list_t *packages);
alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle,
alpm_list_t *upgrade, alpm_list_t *remove);
#endif /* ALPM_CONFLICT_H */

View file

@ -1,773 +0,0 @@
/*
* db.c
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
* Copyright (c) 2006 by David Kimpe <dnaku@frugalware.org>
* Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.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, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <regex.h>
/* libalpm */
#include "db.h"
#include "alpm_list.h"
#include "log.h"
#include "util.h"
#include "handle.h"
#include "alpm.h"
#include "package.h"
#include "group.h"
alpm_db_t SYMEXPORT *alpm_register_syncdb(alpm_handle_t *handle,
const char *treename, int siglevel)
{
alpm_list_t *i;
/* Sanity checks */
CHECK_HANDLE(handle, return NULL);
ASSERT(treename != NULL && strlen(treename) != 0,
RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL));
ASSERT(!strchr(treename, '/'), RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL));
/* Do not register a database if a transaction is on-going */
ASSERT(handle->trans == NULL, RET_ERR(handle, ALPM_ERR_TRANS_NOT_NULL, NULL));
/* ensure database name is unique */
if(strcmp(treename, "local") == 0) {
RET_ERR(handle, ALPM_ERR_DB_NOT_NULL, NULL);
}
for(i = handle->dbs_sync; i; i = i->next) {
alpm_db_t *d = i->data;
if(strcmp(treename, d->treename) == 0) {
RET_ERR(handle, ALPM_ERR_DB_NOT_NULL, NULL);
}
}
return _alpm_db_register_sync(handle, treename, siglevel);
}
/* Helper function for alpm_db_unregister{_all} */
void _alpm_db_unregister(alpm_db_t *db)
{
if(db == NULL) {
return;
}
_alpm_log(db->handle, ALPM_LOG_DEBUG, "unregistering database '%s'\n", db->treename);
_alpm_db_free(db);
}
int SYMEXPORT alpm_unregister_all_syncdbs(alpm_handle_t *handle)
{
alpm_list_t *i;
alpm_db_t *db;
/* Sanity checks */
CHECK_HANDLE(handle, return -1);
/* Do not unregister a database if a transaction is on-going */
ASSERT(handle->trans == NULL, RET_ERR(handle, ALPM_ERR_TRANS_NOT_NULL, -1));
/* unregister all sync dbs */
for(i = handle->dbs_sync; i; i = i->next) {
db = i->data;
db->ops->unregister(db);
i->data = NULL;
}
FREELIST(handle->dbs_sync);
return 0;
}
int SYMEXPORT alpm_db_unregister(alpm_db_t *db)
{
int found = 0;
alpm_handle_t *handle;
/* Sanity checks */
ASSERT(db != NULL, return -1);
/* Do not unregister a database if a transaction is on-going */
handle = db->handle;
handle->pm_errno = ALPM_ERR_OK;
ASSERT(handle->trans == NULL, RET_ERR(handle, ALPM_ERR_TRANS_NOT_NULL, -1));
if(db == handle->db_local) {
handle->db_local = NULL;
found = 1;
} else {
/* Warning : this function shouldn't be used to unregister all sync
* databases by walking through the list returned by
* alpm_get_syncdbs, because the db is removed from that list here.
*/
void *data;
handle->dbs_sync = alpm_list_remove(handle->dbs_sync,
db, _alpm_db_cmp, &data);
if(data) {
found = 1;
}
}
if(!found) {
RET_ERR(handle, ALPM_ERR_DB_NOT_FOUND, -1);
}
db->ops->unregister(db);
return 0;
}
alpm_list_t SYMEXPORT *alpm_db_get_cache_servers(const alpm_db_t *db)
{
ASSERT(db != NULL, return NULL);
return db->cache_servers;
}
int SYMEXPORT alpm_db_set_cache_servers(alpm_db_t *db, alpm_list_t *cache_servers)
{
alpm_list_t *i;
ASSERT(db != NULL, return -1);
FREELIST(db->cache_servers);
for(i = cache_servers; i; i = i->next) {
char *url = i->data;
if(alpm_db_add_cache_server(db, url) != 0) {
return -1;
}
}
return 0;
}
alpm_list_t SYMEXPORT *alpm_db_get_servers(const alpm_db_t *db)
{
ASSERT(db != NULL, return NULL);
return db->servers;
}
int SYMEXPORT alpm_db_set_servers(alpm_db_t *db, alpm_list_t *servers)
{
alpm_list_t *i;
ASSERT(db != NULL, return -1);
FREELIST(db->servers);
for(i = servers; i; i = i->next) {
char *url = i->data;
if(alpm_db_add_server(db, url) != 0) {
return -1;
}
}
return 0;
}
static char *sanitize_url(const char *url)
{
char *newurl;
size_t len = strlen(url);
STRDUP(newurl, url, return NULL);
/* strip the trailing slash if one exists */
if(newurl[len - 1] == '/') {
newurl[len - 1] = '\0';
}
return newurl;
}
int SYMEXPORT alpm_db_add_cache_server(alpm_db_t *db, const char *url)
{
char *newurl;
/* Sanity checks */
ASSERT(db != NULL, return -1);
db->handle->pm_errno = ALPM_ERR_OK;
ASSERT(url != NULL && strlen(url) != 0, RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, -1));
newurl = sanitize_url(url);
ASSERT(newurl != NULL, RET_ERR(db->handle, ALPM_ERR_MEMORY, -1));
db->cache_servers = alpm_list_add(db->cache_servers, newurl);
_alpm_log(db->handle, ALPM_LOG_DEBUG, "adding new cache server URL to database '%s': %s\n",
db->treename, newurl);
return 0;
}
int SYMEXPORT alpm_db_add_server(alpm_db_t *db, const char *url)
{
char *newurl;
/* Sanity checks */
ASSERT(db != NULL, return -1);
db->handle->pm_errno = ALPM_ERR_OK;
ASSERT(url != NULL && strlen(url) != 0, RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, -1));
newurl = sanitize_url(url);
ASSERT(newurl != NULL, RET_ERR(db->handle, ALPM_ERR_MEMORY, -1));
db->servers = alpm_list_add(db->servers, newurl);
_alpm_log(db->handle, ALPM_LOG_DEBUG, "adding new server URL to database '%s': %s\n",
db->treename, newurl);
return 0;
}
int SYMEXPORT alpm_db_remove_cache_server(alpm_db_t *db, const char *url)
{
char *newurl, *vdata = NULL;
int ret = 1;
/* Sanity checks */
ASSERT(db != NULL, return -1);
db->handle->pm_errno = ALPM_ERR_OK;
ASSERT(url != NULL && strlen(url) != 0, RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, -1));
newurl = sanitize_url(url);
ASSERT(newurl != NULL, RET_ERR(db->handle, ALPM_ERR_MEMORY, -1));
db->cache_servers = alpm_list_remove_str(db->cache_servers, newurl, &vdata);
if(vdata) {
_alpm_log(db->handle, ALPM_LOG_DEBUG, "removed cache server URL from database '%s': %s\n",
db->treename, newurl);
free(vdata);
ret = 0;
}
free(newurl);
return ret;
}
int SYMEXPORT alpm_db_remove_server(alpm_db_t *db, const char *url)
{
char *newurl, *vdata = NULL;
int ret = 1;
/* Sanity checks */
ASSERT(db != NULL, return -1);
db->handle->pm_errno = ALPM_ERR_OK;
ASSERT(url != NULL && strlen(url) != 0, RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, -1));
newurl = sanitize_url(url);
ASSERT(newurl != NULL, RET_ERR(db->handle, ALPM_ERR_MEMORY, -1));
db->servers = alpm_list_remove_str(db->servers, newurl, &vdata);
if(vdata) {
_alpm_log(db->handle, ALPM_LOG_DEBUG, "removed server URL from database '%s': %s\n",
db->treename, newurl);
free(vdata);
ret = 0;
}
free(newurl);
return ret;
}
alpm_handle_t SYMEXPORT *alpm_db_get_handle(alpm_db_t *db)
{
ASSERT(db != NULL, return NULL);
return db->handle;
}
const char SYMEXPORT *alpm_db_get_name(const alpm_db_t *db)
{
ASSERT(db != NULL, return NULL);
return db->treename;
}
int SYMEXPORT alpm_db_get_siglevel(alpm_db_t *db)
{
ASSERT(db != NULL, return -1);
if(db->siglevel & ALPM_SIG_USE_DEFAULT) {
return db->handle->siglevel;
} else {
return db->siglevel;
}
}
int SYMEXPORT alpm_db_get_valid(alpm_db_t *db)
{
ASSERT(db != NULL, return -1);
db->handle->pm_errno = ALPM_ERR_OK;
return db->ops->validate(db);
}
alpm_pkg_t SYMEXPORT *alpm_db_get_pkg(alpm_db_t *db, const char *name)
{
alpm_pkg_t *pkg;
ASSERT(db != NULL, return NULL);
db->handle->pm_errno = ALPM_ERR_OK;
ASSERT(name != NULL && strlen(name) != 0,
RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, NULL));
pkg = _alpm_db_get_pkgfromcache(db, name);
if(!pkg) {
RET_ERR(db->handle, ALPM_ERR_PKG_NOT_FOUND, NULL);
}
return pkg;
}
alpm_list_t SYMEXPORT *alpm_db_get_pkgcache(alpm_db_t *db)
{
ASSERT(db != NULL, return NULL);
db->handle->pm_errno = ALPM_ERR_OK;
return _alpm_db_get_pkgcache(db);
}
alpm_group_t SYMEXPORT *alpm_db_get_group(alpm_db_t *db, const char *name)
{
ASSERT(db != NULL, return NULL);
db->handle->pm_errno = 0;
ASSERT(name != NULL && strlen(name) != 0,
RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, NULL));
return _alpm_db_get_groupfromcache(db, name);
}
alpm_list_t SYMEXPORT *alpm_db_get_groupcache(alpm_db_t *db)
{
ASSERT(db != NULL, return NULL);
db->handle->pm_errno = ALPM_ERR_OK;
return _alpm_db_get_groupcache(db);
}
int SYMEXPORT alpm_db_search(alpm_db_t *db, const alpm_list_t *needles,
alpm_list_t **ret)
{
ASSERT(db != NULL && ret != NULL && *ret == NULL,
RET_ERR(db->handle, ALPM_ERR_WRONG_ARGS, -1));
db->handle->pm_errno = ALPM_ERR_OK;
return _alpm_db_search(db, needles, ret);
}
int SYMEXPORT alpm_db_set_usage(alpm_db_t *db, int usage)
{
ASSERT(db != NULL, return -1);
db->usage = usage;
return 0;
}
int SYMEXPORT alpm_db_get_usage(alpm_db_t *db, int *usage)
{
ASSERT(db != NULL, return -1);
ASSERT(usage != NULL, return -1);
*usage = db->usage;
return 0;
}
alpm_db_t *_alpm_db_new(const char *treename, int is_local)
{
alpm_db_t *db;
CALLOC(db, 1, sizeof(alpm_db_t), return NULL);
STRDUP(db->treename, treename, FREE(db); return NULL);
if(is_local) {
db->status |= DB_STATUS_LOCAL;
} else {
db->status &= ~DB_STATUS_LOCAL;
}
db->usage = ALPM_DB_USAGE_ALL;
return db;
}
void _alpm_db_free(alpm_db_t *db)
{
ASSERT(db != NULL, return);
/* cleanup pkgcache */
_alpm_db_free_pkgcache(db);
/* cleanup server list */
FREELIST(db->cache_servers);
FREELIST(db->servers);
FREE(db->_path);
FREE(db->treename);
FREE(db);
return;
}
const char *_alpm_db_path(alpm_db_t *db)
{
if(!db) {
return NULL;
}
if(!db->_path) {
const char *dbpath;
size_t pathsize;
dbpath = db->handle->dbpath;
if(!dbpath) {
_alpm_log(db->handle, ALPM_LOG_ERROR, _("database path is undefined\n"));
RET_ERR(db->handle, ALPM_ERR_DB_OPEN, NULL);
}
if(db->status & DB_STATUS_LOCAL) {
pathsize = strlen(dbpath) + strlen(db->treename) + 2;
CALLOC(db->_path, 1, pathsize, RET_ERR(db->handle, ALPM_ERR_MEMORY, NULL));
snprintf(db->_path, pathsize, "%s%s/", dbpath, db->treename);
} else {
const char *dbext = db->handle->dbext;
pathsize = strlen(dbpath) + 5 + strlen(db->treename) + strlen(dbext) + 1;
CALLOC(db->_path, 1, pathsize, RET_ERR(db->handle, ALPM_ERR_MEMORY, NULL));
/* all sync DBs now reside in the sync/ subdir of the dbpath */
snprintf(db->_path, pathsize, "%ssync/%s%s", dbpath, db->treename, dbext);
}
_alpm_log(db->handle, ALPM_LOG_DEBUG, "database path for tree %s set to %s\n",
db->treename, db->_path);
}
return db->_path;
}
int _alpm_db_cmp(const void *d1, const void *d2)
{
const alpm_db_t *db1 = d1;
const alpm_db_t *db2 = d2;
return strcmp(db1->treename, db2->treename);
}
int _alpm_db_search(alpm_db_t *db, const alpm_list_t *needles,
alpm_list_t **ret)
{
const alpm_list_t *i, *j, *k;
if(!(db->usage & ALPM_DB_USAGE_SEARCH)) {
return 0;
}
/* copy the pkgcache- we will free the list var after each needle */
alpm_list_t *list = alpm_list_copy(_alpm_db_get_pkgcache(db));
for(i = needles; i; i = i->next) {
char *targ;
regex_t reg;
if(i->data == NULL) {
continue;
}
*ret = NULL;
targ = i->data;
_alpm_log(db->handle, ALPM_LOG_DEBUG, "searching for target '%s'\n", targ);
if(regcomp(&reg, targ, REG_EXTENDED | REG_NOSUB | REG_ICASE | REG_NEWLINE) != 0) {
db->handle->pm_errno = ALPM_ERR_INVALID_REGEX;
alpm_list_free(list);
alpm_list_free(*ret);
return -1;
}
for(j = list; j; j = j->next) {
alpm_pkg_t *pkg = j->data;
const char *matched = NULL;
const char *name = pkg->name;
const char *desc = alpm_pkg_get_desc(pkg);
/* check name as regex AND as plain text */
if(name && (regexec(&reg, name, 0, 0, 0) == 0 || strstr(name, targ))) {
matched = name;
}
/* check desc */
else if(desc && regexec(&reg, desc, 0, 0, 0) == 0) {
matched = desc;
}
/* TODO: should we be doing this, and should we print something
* differently when we do match it since it isn't currently printed? */
if(!matched) {
/* check provides */
for(k = alpm_pkg_get_provides(pkg); k; k = k->next) {
alpm_depend_t *provide = k->data;
if(regexec(&reg, provide->name, 0, 0, 0) == 0) {
matched = provide->name;
break;
}
}
}
if(!matched) {
/* check groups */
for(k = alpm_pkg_get_groups(pkg); k; k = k->next) {
if(regexec(&reg, k->data, 0, 0, 0) == 0) {
matched = k->data;
break;
}
}
}
if(matched != NULL) {
_alpm_log(db->handle, ALPM_LOG_DEBUG,
"search target '%s' matched '%s' on package '%s'\n",
targ, matched, name);
*ret = alpm_list_add(*ret, pkg);
}
}
/* Free the existing search list, and use the returned list for the
* next needle. This allows for AND-based package searching. */
alpm_list_free(list);
list = *ret;
regfree(&reg);
}
return 0;
}
/* Returns a new package cache from db.
* It frees the cache if it already exists.
*/
static int load_pkgcache(alpm_db_t *db)
{
_alpm_db_free_pkgcache(db);
_alpm_log(db->handle, ALPM_LOG_DEBUG, "loading package cache for repository '%s'\n",
db->treename);
if(db->ops->populate(db) == -1) {
_alpm_log(db->handle, ALPM_LOG_DEBUG,
"failed to load package cache for repository '%s'\n", db->treename);
return -1;
}
db->status |= DB_STATUS_PKGCACHE;
return 0;
}
static void free_groupcache(alpm_db_t *db)
{
alpm_list_t *lg;
if(db == NULL || !(db->status & DB_STATUS_GRPCACHE)) {
return;
}
_alpm_log(db->handle, ALPM_LOG_DEBUG,
"freeing group cache for repository '%s'\n", db->treename);
for(lg = db->grpcache; lg; lg = lg->next) {
_alpm_group_free(lg->data);
lg->data = NULL;
}
FREELIST(db->grpcache);
db->status &= ~DB_STATUS_GRPCACHE;
}
void _alpm_db_free_pkgcache(alpm_db_t *db)
{
if(db == NULL || db->pkgcache == NULL) {
return;
}
_alpm_log(db->handle, ALPM_LOG_DEBUG,
"freeing package cache for repository '%s'\n", db->treename);
alpm_list_free_inner(db->pkgcache->list,
(alpm_list_fn_free)_alpm_pkg_free);
_alpm_pkghash_free(db->pkgcache);
db->pkgcache = NULL;
db->status &= ~DB_STATUS_PKGCACHE;
free_groupcache(db);
}
alpm_pkghash_t *_alpm_db_get_pkgcache_hash(alpm_db_t *db)
{
if(db == NULL) {
return NULL;
}
if(!(db->status & DB_STATUS_VALID)) {
RET_ERR(db->handle, ALPM_ERR_DB_INVALID, NULL);
}
if(!(db->status & DB_STATUS_PKGCACHE)) {
if(load_pkgcache(db)) {
/* handle->error set in local/sync-db-populate */
return NULL;
}
}
return db->pkgcache;
}
alpm_list_t *_alpm_db_get_pkgcache(alpm_db_t *db)
{
alpm_pkghash_t *hash = _alpm_db_get_pkgcache_hash(db);
if(hash == NULL) {
return NULL;
}
return hash->list;
}
/* "duplicate" pkg then add it to pkgcache */
int _alpm_db_add_pkgincache(alpm_db_t *db, alpm_pkg_t *pkg)
{
alpm_pkg_t *newpkg = NULL;
if(db == NULL || pkg == NULL || !(db->status & DB_STATUS_PKGCACHE)) {
return -1;
}
if(_alpm_pkg_dup(pkg, &newpkg)) {
/* we return memory on "non-fatal" error in _alpm_pkg_dup */
_alpm_pkg_free(newpkg);
return -1;
}
_alpm_log(db->handle, ALPM_LOG_DEBUG, "adding entry '%s' in '%s' cache\n",
newpkg->name, db->treename);
if(newpkg->origin == ALPM_PKG_FROM_FILE) {
free(newpkg->origin_data.file);
}
newpkg->origin = (db->status & DB_STATUS_LOCAL)
? ALPM_PKG_FROM_LOCALDB
: ALPM_PKG_FROM_SYNCDB;
newpkg->origin_data.db = db;
if(_alpm_pkghash_add_sorted(&db->pkgcache, newpkg) == NULL) {
_alpm_pkg_free(newpkg);
RET_ERR(db->handle, ALPM_ERR_MEMORY, -1);
}
free_groupcache(db);
return 0;
}
int _alpm_db_remove_pkgfromcache(alpm_db_t *db, alpm_pkg_t *pkg)
{
alpm_pkg_t *data = NULL;
if(db == NULL || pkg == NULL || !(db->status & DB_STATUS_PKGCACHE)) {
return -1;
}
_alpm_log(db->handle, ALPM_LOG_DEBUG, "removing entry '%s' from '%s' cache\n",
pkg->name, db->treename);
db->pkgcache = _alpm_pkghash_remove(db->pkgcache, pkg, &data);
if(data == NULL) {
/* package not found */
_alpm_log(db->handle, ALPM_LOG_DEBUG, "cannot remove entry '%s' from '%s' cache: not found\n",
pkg->name, db->treename);
return -1;
}
_alpm_pkg_free(data);
free_groupcache(db);
return 0;
}
alpm_pkg_t *_alpm_db_get_pkgfromcache(alpm_db_t *db, const char *target)
{
if(db == NULL) {
return NULL;
}
alpm_pkghash_t *pkgcache = _alpm_db_get_pkgcache_hash(db);
if(!pkgcache) {
return NULL;
}
return _alpm_pkghash_find(pkgcache, target);
}
/* Returns a new group cache from db.
*/
static int load_grpcache(alpm_db_t *db)
{
alpm_list_t *lp;
if(db == NULL) {
return -1;
}
_alpm_log(db->handle, ALPM_LOG_DEBUG, "loading group cache for repository '%s'\n",
db->treename);
for(lp = _alpm_db_get_pkgcache(db); lp; lp = lp->next) {
const alpm_list_t *i;
alpm_pkg_t *pkg = lp->data;
for(i = alpm_pkg_get_groups(pkg); i; i = i->next) {
const char *grpname = i->data;
alpm_list_t *j;
alpm_group_t *grp = NULL;
int found = 0;
/* first look through the group cache for a group with this name */
for(j = db->grpcache; j; j = j->next) {
grp = j->data;
if(strcmp(grp->name, grpname) == 0
&& !alpm_list_find_ptr(grp->packages, pkg)) {
grp->packages = alpm_list_add(grp->packages, pkg);
found = 1;
break;
}
}
if(found) {
continue;
}
/* we didn't find the group, so create a new one with this name */
grp = _alpm_group_new(grpname);
if(!grp) {
free_groupcache(db);
return -1;
}
grp->packages = alpm_list_add(grp->packages, pkg);
db->grpcache = alpm_list_add(db->grpcache, grp);
}
}
db->status |= DB_STATUS_GRPCACHE;
return 0;
}
alpm_list_t *_alpm_db_get_groupcache(alpm_db_t *db)
{
if(db == NULL) {
return NULL;
}
if(!(db->status & DB_STATUS_VALID)) {
RET_ERR(db->handle, ALPM_ERR_DB_INVALID, NULL);
}
if(!(db->status & DB_STATUS_GRPCACHE)) {
load_grpcache(db);
}
return db->grpcache;
}
alpm_group_t *_alpm_db_get_groupfromcache(alpm_db_t *db, const char *target)
{
alpm_list_t *i;
if(db == NULL || target == NULL || strlen(target) == 0) {
return NULL;
}
for(i = _alpm_db_get_groupcache(db); i; i = i->next) {
alpm_group_t *info = i->data;
if(strcmp(info->name, target) == 0) {
return info;
}
}
return NULL;
}

View file

@ -1,116 +0,0 @@
/*
* db.h
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.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, see <http://www.gnu.org/licenses/>.
*/
#ifndef ALPM_DB_H
#define ALPM_DB_H
/* libarchive */
#include <archive.h>
#include <archive_entry.h>
#include "alpm.h"
#include "pkghash.h"
#include "signing.h"
/* Database entries */
typedef enum _alpm_dbinfrq_t {
INFRQ_BASE = (1 << 0),
INFRQ_DESC = (1 << 1),
INFRQ_FILES = (1 << 2),
INFRQ_SCRIPTLET = (1 << 3),
INFRQ_DSIZE = (1 << 4),
/* ALL should be info stored in the package or database */
INFRQ_ALL = INFRQ_BASE | INFRQ_DESC | INFRQ_FILES |
INFRQ_SCRIPTLET | INFRQ_DSIZE,
INFRQ_ERROR = (1 << 30)
} alpm_dbinfrq_t;
/** Database status. Bitflags. */
enum _alpm_dbstatus_t {
DB_STATUS_VALID = (1 << 0),
DB_STATUS_INVALID = (1 << 1),
DB_STATUS_EXISTS = (1 << 2),
DB_STATUS_MISSING = (1 << 3),
DB_STATUS_LOCAL = (1 << 10),
DB_STATUS_PKGCACHE = (1 << 11),
DB_STATUS_GRPCACHE = (1 << 12)
};
struct db_operations {
int (*validate) (alpm_db_t *);
int (*populate) (alpm_db_t *);
void (*unregister) (alpm_db_t *);
};
/* Database */
struct _alpm_db_t {
alpm_handle_t *handle;
char *treename;
/* do not access directly, use _alpm_db_path(db) for lazy access */
char *_path;
alpm_pkghash_t *pkgcache;
alpm_list_t *grpcache;
alpm_list_t *cache_servers;
alpm_list_t *servers;
const struct db_operations *ops;
/* bitfields for validity, local, loaded caches, etc. */
/* From _alpm_dbstatus_t */
int status;
/* alpm_siglevel_t */
int siglevel;
/* alpm_db_usage_t */
int usage;
};
/* db.c, database general calls */
alpm_db_t *_alpm_db_new(const char *treename, int is_local);
void _alpm_db_free(alpm_db_t *db);
const char *_alpm_db_path(alpm_db_t *db);
int _alpm_db_cmp(const void *d1, const void *d2);
int _alpm_db_search(alpm_db_t *db, const alpm_list_t *needles,
alpm_list_t **ret);
alpm_db_t *_alpm_db_register_local(alpm_handle_t *handle);
alpm_db_t *_alpm_db_register_sync(alpm_handle_t *handle, const char *treename,
int level);
void _alpm_db_unregister(alpm_db_t *db);
/* be_*.c, backend specific calls */
int _alpm_local_db_prepare(alpm_db_t *db, alpm_pkg_t *info);
int _alpm_local_db_write(alpm_db_t *db, alpm_pkg_t *info, int inforeq);
int _alpm_local_db_remove(alpm_db_t *db, alpm_pkg_t *info);
char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info, const char *filename);
/* cache bullshit */
/* packages */
void _alpm_db_free_pkgcache(alpm_db_t *db);
int _alpm_db_add_pkgincache(alpm_db_t *db, alpm_pkg_t *pkg);
int _alpm_db_remove_pkgfromcache(alpm_db_t *db, alpm_pkg_t *pkg);
alpm_pkghash_t *_alpm_db_get_pkgcache_hash(alpm_db_t *db);
alpm_list_t *_alpm_db_get_pkgcache(alpm_db_t *db);
alpm_pkg_t *_alpm_db_get_pkgfromcache(alpm_db_t *db, const char *target);
/* groups */
alpm_list_t *_alpm_db_get_groupcache(alpm_db_t *db);
alpm_group_t *_alpm_db_get_groupfromcache(alpm_db_t *db, const char *target);
#endif /* ALPM_DB_H */

View file

@ -1,926 +0,0 @@
/*
* deps.c
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* libalpm */
#include "deps.h"
#include "alpm_list.h"
#include "util.h"
#include "log.h"
#include "graph.h"
#include "package.h"
#include "db.h"
#include "handle.h"
#include "trans.h"
void SYMEXPORT alpm_dep_free(alpm_depend_t *dep)
{
ASSERT(dep != NULL, return);
FREE(dep->name);
FREE(dep->version);
FREE(dep->desc);
FREE(dep);
}
static alpm_depmissing_t *depmiss_new(const char *target, alpm_depend_t *dep,
const char *causingpkg)
{
alpm_depmissing_t *miss;
CALLOC(miss, 1, sizeof(alpm_depmissing_t), return NULL);
STRDUP(miss->target, target, goto error);
miss->depend = _alpm_dep_dup(dep);
STRDUP(miss->causingpkg, causingpkg, goto error);
return miss;
error:
alpm_depmissing_free(miss);
return NULL;
}
void SYMEXPORT alpm_depmissing_free(alpm_depmissing_t *miss)
{
ASSERT(miss != NULL, return);
alpm_dep_free(miss->depend);
FREE(miss->target);
FREE(miss->causingpkg);
FREE(miss);
}
/** Check if pkg2 satisfies a dependency of pkg1 */
static int _alpm_pkg_depends_on(alpm_pkg_t *pkg1, alpm_pkg_t *pkg2)
{
alpm_list_t *i;
for(i = alpm_pkg_get_depends(pkg1); i; i = i->next) {
if(_alpm_depcmp(pkg2, i->data)) {
return 1;
}
}
return 0;
}
static alpm_pkg_t *find_dep_satisfier(alpm_list_t *pkgs, alpm_depend_t *dep)
{
alpm_list_t *i;
for(i = pkgs; i; i = i->next) {
alpm_pkg_t *pkg = i->data;
if(_alpm_depcmp(pkg, dep)) {
return pkg;
}
}
return NULL;
}
/* Convert a list of alpm_pkg_t * to a graph structure,
* with a edge for each dependency.
* Returns a list of vertices (one vertex = one package)
* (used by alpm_sortbydeps)
*/
static alpm_list_t *dep_graph_init(alpm_handle_t *handle,
alpm_list_t *targets, alpm_list_t *ignore)
{
alpm_list_t *i, *j;
alpm_list_t *vertices = NULL;
alpm_list_t *localpkgs = alpm_list_diff(
alpm_db_get_pkgcache(handle->db_local), targets, _alpm_pkg_cmp);
if(ignore) {
alpm_list_t *oldlocal = localpkgs;
localpkgs = alpm_list_diff(oldlocal, ignore, _alpm_pkg_cmp);
alpm_list_free(oldlocal);
}
/* We create the vertices */
for(i = targets; i; i = i->next) {
alpm_graph_t *vertex = _alpm_graph_new();
vertex->data = (void *)i->data;
vertices = alpm_list_add(vertices, vertex);
}
/* We compute the edges */
for(i = vertices; i; i = i->next) {
alpm_graph_t *vertex_i = i->data;
alpm_pkg_t *p_i = vertex_i->data;
/* TODO this should be somehow combined with alpm_checkdeps */
for(j = vertices; j; j = j->next) {
alpm_graph_t *vertex_j = j->data;
alpm_pkg_t *p_j = vertex_j->data;
if(_alpm_pkg_depends_on(p_i, p_j)) {
vertex_i->children =
alpm_list_add(vertex_i->children, vertex_j);
}
}
/* lazily add local packages to the dep graph so they don't
* get resolved unnecessarily */
j = localpkgs;
while(j) {
alpm_list_t *next = j->next;
if(_alpm_pkg_depends_on(p_i, j->data)) {
alpm_graph_t *vertex_j = _alpm_graph_new();
vertex_j->data = (void *)j->data;
vertices = alpm_list_add(vertices, vertex_j);
vertex_i->children = alpm_list_add(vertex_i->children, vertex_j);
localpkgs = alpm_list_remove_item(localpkgs, j);
free(j);
}
j = next;
}
vertex_i->iterator = vertex_i->children;
}
alpm_list_free(localpkgs);
return vertices;
}
static void _alpm_warn_dep_cycle(alpm_handle_t *handle, alpm_list_t *targets,
alpm_graph_t *ancestor, alpm_graph_t *vertex, int reverse)
{
/* vertex depends on and is required by ancestor */
if(!alpm_list_find_ptr(targets, vertex->data)) {
/* child is not part of the transaction, not a problem */
return;
}
/* find the nearest ancestor that's part of the transaction */
while(ancestor) {
if(alpm_list_find_ptr(targets, ancestor->data)) {
break;
}
ancestor = ancestor->parent;
}
if(!ancestor || ancestor == vertex) {
/* no transaction package in our ancestry or the package has
* a circular dependency with itself, not a problem */
} else {
alpm_pkg_t *ancestorpkg = ancestor->data;
alpm_pkg_t *childpkg = vertex->data;
_alpm_log(handle, ALPM_LOG_DEBUG, _("dependency cycle detected:\n"));
if(reverse) {
_alpm_log(handle, ALPM_LOG_DEBUG,
_("%s will be removed after its %s dependency\n"),
ancestorpkg->name, childpkg->name);
} else {
_alpm_log(handle, ALPM_LOG_DEBUG,
_("%s will be installed before its %s dependency\n"),
ancestorpkg->name, childpkg->name);
}
}
}
/* Re-order a list of target packages with respect to their dependencies.
*
* Example (reverse == 0):
* A depends on C
* B depends on A
* Target order is A,B,C,D
*
* Should be re-ordered to C,A,B,D
*
* packages listed in ignore will not be used to detect indirect dependencies
*
* if reverse is > 0, the dependency order will be reversed.
*
* This function returns the new alpm_list_t* target list.
*
*/
alpm_list_t *_alpm_sortbydeps(alpm_handle_t *handle,
alpm_list_t *targets, alpm_list_t *ignore, int reverse)
{
alpm_list_t *newtargs = NULL;
alpm_list_t *vertices = NULL;
alpm_list_t *i;
alpm_graph_t *vertex;
if(targets == NULL) {
return NULL;
}
_alpm_log(handle, ALPM_LOG_DEBUG, "started sorting dependencies\n");
vertices = dep_graph_init(handle, targets, ignore);
i = vertices;
vertex = vertices->data;
while(i) {
/* mark that we touched the vertex */
vertex->state = ALPM_GRAPH_STATE_PROCESSING;
int switched_to_child = 0;
while(vertex->iterator && !switched_to_child) {
alpm_graph_t *nextchild = vertex->iterator->data;
vertex->iterator = vertex->iterator->next;
if(nextchild->state == ALPM_GRAPH_STATE_UNPROCESSED) {
switched_to_child = 1;
nextchild->parent = vertex;
vertex = nextchild;
} else if(nextchild->state == ALPM_GRAPH_STATE_PROCESSING) {
_alpm_warn_dep_cycle(handle, targets, vertex, nextchild, reverse);
}
}
if(!switched_to_child) {
if(alpm_list_find_ptr(targets, vertex->data)) {
newtargs = alpm_list_add(newtargs, vertex->data);
}
/* mark that we've left this vertex */
vertex->state = ALPM_GRAPH_STATE_PROCESSED;
vertex = vertex->parent;
if(!vertex) {
/* top level vertex reached, move to the next unprocessed vertex */
for(i = i->next; i; i = i->next) {
vertex = i->data;
if(vertex->state == ALPM_GRAPH_STATE_UNPROCESSED) {
break;
}
}
}
}
}
_alpm_log(handle, ALPM_LOG_DEBUG, "sorting dependencies finished\n");
if(reverse) {
/* reverse the order */
alpm_list_t *tmptargs = alpm_list_reverse(newtargs);
/* free the old one */
alpm_list_free(newtargs);
newtargs = tmptargs;
}
alpm_list_free_inner(vertices, _alpm_graph_free);
alpm_list_free(vertices);
return newtargs;
}
static int no_dep_version(alpm_handle_t *handle)
{
if(!handle->trans) {
return 0;
}
return (handle->trans->flags & ALPM_TRANS_FLAG_NODEPVERSION);
}
alpm_pkg_t SYMEXPORT *alpm_find_satisfier(alpm_list_t *pkgs, const char *depstring)
{
alpm_depend_t *dep = alpm_dep_from_string(depstring);
if(!dep) {
return NULL;
}
alpm_pkg_t *pkg = find_dep_satisfier(pkgs, dep);
alpm_dep_free(dep);
return pkg;
}
alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_handle_t *handle,
alpm_list_t *pkglist, alpm_list_t *rem, alpm_list_t *upgrade,
int reversedeps)
{
alpm_list_t *i, *j;
alpm_list_t *dblist = NULL, *modified = NULL;
alpm_list_t *baddeps = NULL;
int nodepversion;
CHECK_HANDLE(handle, return NULL);
for(i = pkglist; i; i = i->next) {
alpm_pkg_t *pkg = i->data;
if(alpm_pkg_find(rem, pkg->name) || alpm_pkg_find(upgrade, pkg->name)) {
modified = alpm_list_add(modified, pkg);
} else {
dblist = alpm_list_add(dblist, pkg);
}
}
nodepversion = no_dep_version(handle);
/* look for unsatisfied dependencies of the upgrade list */
for(i = upgrade; i; i = i->next) {
alpm_pkg_t *tp = i->data;
_alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: package %s-%s\n",
tp->name, tp->version);
for(j = alpm_pkg_get_depends(tp); j; j = j->next) {
alpm_depend_t *depend = j->data;
alpm_depmod_t orig_mod = depend->mod;
if(nodepversion) {
depend->mod = ALPM_DEP_MOD_ANY;
}
/* 1. we check the upgrade list */
/* 2. we check database for untouched satisfying packages */
/* 3. we check the dependency ignore list */
if(!find_dep_satisfier(upgrade, depend) &&
!find_dep_satisfier(dblist, depend) &&
!_alpm_depcmp_provides(depend, handle->assumeinstalled)) {
/* Unsatisfied dependency in the upgrade list */
alpm_depmissing_t *miss;
char *missdepstring = alpm_dep_compute_string(depend);
_alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: missing dependency '%s' for package '%s'\n",
missdepstring, tp->name);
free(missdepstring);
miss = depmiss_new(tp->name, depend, NULL);
baddeps = alpm_list_add(baddeps, miss);
}
depend->mod = orig_mod;
}
}
if(reversedeps) {
/* reversedeps handles the backwards dependencies, ie,
* the packages listed in the requiredby field. */
for(i = dblist; i; i = i->next) {
alpm_pkg_t *lp = i->data;
for(j = alpm_pkg_get_depends(lp); j; j = j->next) {
alpm_depend_t *depend = j->data;
alpm_depmod_t orig_mod = depend->mod;
if(nodepversion) {
depend->mod = ALPM_DEP_MOD_ANY;
}
alpm_pkg_t *causingpkg = find_dep_satisfier(modified, depend);
/* we won't break this depend, if it is already broken, we ignore it */
/* 1. check upgrade list for satisfiers */
/* 2. check dblist for satisfiers */
/* 3. we check the dependency ignore list */
if(causingpkg &&
!find_dep_satisfier(upgrade, depend) &&
!find_dep_satisfier(dblist, depend) &&
!_alpm_depcmp_provides(depend, handle->assumeinstalled)) {
alpm_depmissing_t *miss;
char *missdepstring = alpm_dep_compute_string(depend);
_alpm_log(handle, ALPM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n",
missdepstring, lp->name);
free(missdepstring);
miss = depmiss_new(lp->name, depend, causingpkg->name);
baddeps = alpm_list_add(baddeps, miss);
}
depend->mod = orig_mod;
}
}
}
alpm_list_free(modified);
alpm_list_free(dblist);
return baddeps;
}
static int dep_vercmp(const char *version1, alpm_depmod_t mod,
const char *version2)
{
int equal = 0;
if(mod == ALPM_DEP_MOD_ANY) {
equal = 1;
} else {
int cmp = alpm_pkg_vercmp(version1, version2);
switch(mod) {
case ALPM_DEP_MOD_EQ: equal = (cmp == 0); break;
case ALPM_DEP_MOD_GE: equal = (cmp >= 0); break;
case ALPM_DEP_MOD_LE: equal = (cmp <= 0); break;
case ALPM_DEP_MOD_LT: equal = (cmp < 0); break;
case ALPM_DEP_MOD_GT: equal = (cmp > 0); break;
default: equal = 1; break;
}
}
return equal;
}
int _alpm_depcmp_literal(alpm_pkg_t *pkg, alpm_depend_t *dep)
{
if(pkg->name_hash != dep->name_hash
|| strcmp(pkg->name, dep->name) != 0) {
/* skip more expensive checks */
return 0;
}
return dep_vercmp(pkg->version, dep->mod, dep->version);
}
/**
* @param dep dependency to check against the provision list
* @param provisions provision list
* @return 1 if provider is found, 0 otherwise
*/
int _alpm_depcmp_provides(alpm_depend_t *dep, alpm_list_t *provisions)
{
int satisfy = 0;
alpm_list_t *i;
/* check provisions, name and version if available */
for(i = provisions; i && !satisfy; i = i->next) {
alpm_depend_t *provision = i->data;
if(dep->mod == ALPM_DEP_MOD_ANY) {
/* any version will satisfy the requirement */
satisfy = (provision->name_hash == dep->name_hash
&& strcmp(provision->name, dep->name) == 0);
} else if(provision->mod == ALPM_DEP_MOD_EQ) {
/* provision specifies a version, so try it out */
satisfy = (provision->name_hash == dep->name_hash
&& strcmp(provision->name, dep->name) == 0
&& dep_vercmp(provision->version, dep->mod, dep->version));
}
}
return satisfy;
}
int _alpm_depcmp(alpm_pkg_t *pkg, alpm_depend_t *dep)
{
return _alpm_depcmp_literal(pkg, dep)
|| _alpm_depcmp_provides(dep, alpm_pkg_get_provides(pkg));
}
alpm_depend_t SYMEXPORT *alpm_dep_from_string(const char *depstring)
{
alpm_depend_t *depend;
const char *ptr, *version, *desc;
size_t deplen;
if(depstring == NULL) {
return NULL;
}
CALLOC(depend, 1, sizeof(alpm_depend_t), return NULL);
/* Note the extra space in ": " to avoid matching the epoch */
if((desc = strstr(depstring, ": ")) != NULL) {
STRDUP(depend->desc, desc + 2, goto error);
deplen = desc - depstring;
} else {
/* no description- point desc at NULL at end of string for later use */
depend->desc = NULL;
deplen = strlen(depstring);
desc = depstring + deplen;
}
/* Find a version comparator if one exists. If it does, set the type and
* increment the ptr accordingly so we can copy the right strings. */
if((ptr = memchr(depstring, '<', deplen))) {
if(ptr[1] == '=') {
depend->mod = ALPM_DEP_MOD_LE;
version = ptr + 2;
} else {
depend->mod = ALPM_DEP_MOD_LT;
version = ptr + 1;
}
} else if((ptr = memchr(depstring, '>', deplen))) {
if(ptr[1] == '=') {
depend->mod = ALPM_DEP_MOD_GE;
version = ptr + 2;
} else {
depend->mod = ALPM_DEP_MOD_GT;
version = ptr + 1;
}
} else if((ptr = memchr(depstring, '=', deplen))) {
/* Note: we must do =,<,> checks after <=, >= checks */
depend->mod = ALPM_DEP_MOD_EQ;
version = ptr + 1;
} else {
/* no version specified, set ptr to end of string and version to NULL */
ptr = depstring + deplen;
depend->mod = ALPM_DEP_MOD_ANY;
depend->version = NULL;
version = NULL;
}
/* copy the right parts to the right places */
STRNDUP(depend->name, depstring, ptr - depstring, goto error);
depend->name_hash = _alpm_hash_sdbm(depend->name);
if(version) {
STRNDUP(depend->version, version, desc - version, goto error);
}
return depend;
error:
alpm_dep_free(depend);
return NULL;
}
alpm_depend_t *_alpm_dep_dup(const alpm_depend_t *dep)
{
alpm_depend_t *newdep;
CALLOC(newdep, 1, sizeof(alpm_depend_t), return NULL);
STRDUP(newdep->name, dep->name, goto error);
STRDUP(newdep->version, dep->version, goto error);
STRDUP(newdep->desc, dep->desc, goto error);
newdep->name_hash = dep->name_hash;
newdep->mod = dep->mod;
return newdep;
error:
alpm_dep_free(newdep);
return NULL;
}
/** Move package dependencies from one list to another
* @param from list to scan for dependencies
* @param to list to add dependencies to
* @param pkg package whose dependencies are moved
* @param explicit if 0, explicitly installed packages are not moved
*/
static void _alpm_select_depends(alpm_list_t **from, alpm_list_t **to,
alpm_pkg_t *pkg, int explicit)
{
alpm_list_t *i, *next;
if(!alpm_pkg_get_depends(pkg)) {
return;
}
for(i = *from; i; i = next) {
alpm_pkg_t *deppkg = i->data;
next = i->next;
if((explicit || alpm_pkg_get_reason(deppkg) == ALPM_PKG_REASON_DEPEND)
&& _alpm_pkg_depends_on(pkg, deppkg)) {
*to = alpm_list_add(*to, deppkg);
*from = alpm_list_remove_item(*from, i);
free(i);
}
}
}
/**
* @brief Adds unneeded dependencies to an existing list of packages.
* By unneeded, we mean dependencies that are only required by packages in the
* target list, so they can be safely removed.
* If the input list was topo sorted, the output list will be topo sorted too.
*
* @param db package database to do dependency tracing in
* @param *targs pointer to a list of packages
* @param include_explicit if 0, explicitly installed packages are not included
* @return 0 on success, -1 on errors
*/
int _alpm_recursedeps(alpm_db_t *db, alpm_list_t **targs, int include_explicit)
{
alpm_list_t *i, *keep, *rem = NULL;
if(db == NULL || targs == NULL) {
return -1;
}
keep = alpm_list_copy(_alpm_db_get_pkgcache(db));
for(i = *targs; i; i = i->next) {
keep = alpm_list_remove(keep, i->data, _alpm_pkg_cmp, NULL);
}
/* recursively select all dependencies for removal */
for(i = *targs; i; i = i->next) {
_alpm_select_depends(&keep, &rem, i->data, include_explicit);
}
for(i = rem; i; i = i->next) {
_alpm_select_depends(&keep, &rem, i->data, include_explicit);
}
/* recursively select any still needed packages to keep */
for(i = keep; i && rem; i = i->next) {
_alpm_select_depends(&rem, &keep, i->data, 1);
}
alpm_list_free(keep);
/* copy selected packages into the target list */
for(i = rem; i; i = i->next) {
alpm_pkg_t *pkg = i->data, *copy = NULL;
_alpm_log(db->handle, ALPM_LOG_DEBUG,
"adding '%s' to the targets\n", pkg->name);
if(_alpm_pkg_dup(pkg, &copy)) {
/* we return memory on "non-fatal" error in _alpm_pkg_dup */
_alpm_pkg_free(copy);
alpm_list_free(rem);
return -1;
}
*targs = alpm_list_add(*targs, copy);
}
alpm_list_free(rem);
return 0;
}
/**
* helper function for resolvedeps: search for dep satisfier in dbs
*
* @param handle the context handle
* @param dep is the dependency to search for
* @param dbs are the databases to search
* @param excluding are the packages to exclude from the search
* @param prompt if true, ask an alpm_question_install_ignorepkg_t to decide
* if ignored packages should be installed; if false, skip ignored
* packages.
* @return the resolved package
**/
static alpm_pkg_t *resolvedep(alpm_handle_t *handle, alpm_depend_t *dep,
alpm_list_t *dbs, alpm_list_t *excluding, int prompt)
{
alpm_list_t *i, *j;
int ignored = 0;
alpm_list_t *providers = NULL;
int count;
/* 1. literals */
for(i = dbs; i; i = i->next) {
alpm_pkg_t *pkg;
alpm_db_t *db = i->data;
if(!(db->usage & (ALPM_DB_USAGE_INSTALL|ALPM_DB_USAGE_UPGRADE))) {
continue;
}
pkg = _alpm_db_get_pkgfromcache(db, dep->name);
if(pkg && _alpm_depcmp_literal(pkg, dep)
&& !alpm_pkg_find(excluding, pkg->name)) {
if(alpm_pkg_should_ignore(handle, pkg)) {
alpm_question_install_ignorepkg_t question = {
.type = ALPM_QUESTION_INSTALL_IGNOREPKG,
.install = 0,
.pkg = pkg
};
if(prompt) {
QUESTION(handle, &question);
} else {
_alpm_log(handle, ALPM_LOG_WARNING, _("ignoring package %s-%s\n"),
pkg->name, pkg->version);
}
if(!question.install) {
ignored = 1;
continue;
}
}
return pkg;
}
}
/* 2. satisfiers (skip literals here) */
for(i = dbs; i; i = i->next) {
alpm_db_t *db = i->data;
if(!(db->usage & (ALPM_DB_USAGE_INSTALL|ALPM_DB_USAGE_UPGRADE))) {
continue;
}
for(j = _alpm_db_get_pkgcache(db); j; j = j->next) {
alpm_pkg_t *pkg = j->data;
if((pkg->name_hash != dep->name_hash || strcmp(pkg->name, dep->name) != 0)
&& _alpm_depcmp_provides(dep, alpm_pkg_get_provides(pkg))
&& !alpm_pkg_find(excluding, pkg->name)) {
if(alpm_pkg_should_ignore(handle, pkg)) {
alpm_question_install_ignorepkg_t question = {
.type = ALPM_QUESTION_INSTALL_IGNOREPKG,
.install = 0,
.pkg = pkg
};
if(prompt) {
QUESTION(handle, &question);
} else {
_alpm_log(handle, ALPM_LOG_WARNING, _("ignoring package %s-%s\n"),
pkg->name, pkg->version);
}
if(!question.install) {
ignored = 1;
continue;
}
}
_alpm_log(handle, ALPM_LOG_DEBUG, "provider found (%s provides %s)\n",
pkg->name, dep->name);
/* provide is already installed so return early instead of prompting later */
if(_alpm_db_get_pkgfromcache(handle->db_local, pkg->name)) {
alpm_list_free(providers);
return pkg;
}
providers = alpm_list_add(providers, pkg);
/* keep looking for other providers in the all dbs */
}
}
}
count = alpm_list_count(providers);
if(count >= 1) {
alpm_question_select_provider_t question = {
.type = ALPM_QUESTION_SELECT_PROVIDER,
/* default to first provider if there is no QUESTION callback */
.use_index = 0,
.providers = providers,
.depend = dep
};
if(count > 1) {
/* if there is more than one provider, we ask the user */
QUESTION(handle, &question);
}
if(question.use_index >= 0 && question.use_index < count) {
alpm_list_t *nth = alpm_list_nth(providers, question.use_index);
alpm_pkg_t *pkg = nth->data;
alpm_list_free(providers);
return pkg;
}
alpm_list_free(providers);
providers = NULL;
}
if(ignored) { /* resolvedeps will override these */
handle->pm_errno = ALPM_ERR_PKG_IGNORED;
} else {
handle->pm_errno = ALPM_ERR_PKG_NOT_FOUND;
}
return NULL;
}
alpm_pkg_t SYMEXPORT *alpm_find_dbs_satisfier(alpm_handle_t *handle,
alpm_list_t *dbs, const char *depstring)
{
alpm_depend_t *dep;
alpm_pkg_t *pkg;
CHECK_HANDLE(handle, return NULL);
ASSERT(dbs, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, NULL));
dep = alpm_dep_from_string(depstring);
ASSERT(dep, return NULL);
pkg = resolvedep(handle, dep, dbs, NULL, 1);
alpm_dep_free(dep);
return pkg;
}
/**
* Computes resolvable dependencies for a given package and adds that package
* and those resolvable dependencies to a list.
*
* @param handle the context handle
* @param localpkgs is the list of local packages
* @param pkg is the package to resolve
* @param preferred packages to prefer when resolving
* @param packages is a pointer to a list of packages which will be
* searched first for any dependency packages needed to complete the
* resolve, and to which will be added any [pkg] and all of its
* dependencies not already on the list
* @param remove is the set of packages which will be removed in this
* transaction
* @param data returns the dependency which could not be satisfied in the
* event of an error
* @return 0 on success, with [pkg] and all of its dependencies not already on
* the [*packages] list added to that list, or -1 on failure due to an
* unresolvable dependency, in which case the [*packages] list will be
* unmodified by this function
*/
int _alpm_resolvedeps(alpm_handle_t *handle, alpm_list_t *localpkgs,
alpm_pkg_t *pkg, alpm_list_t *preferred, alpm_list_t **packages,
alpm_list_t *rem, alpm_list_t **data)
{
int ret = 0;
alpm_list_t *j;
alpm_list_t *targ;
alpm_list_t *deps = NULL;
alpm_list_t *packages_copy;
if(alpm_pkg_find(*packages, pkg->name) != NULL) {
return 0;
}
/* Create a copy of the packages list, so that it can be restored
on error */
packages_copy = alpm_list_copy(*packages);
/* [pkg] has not already been resolved into the packages list, so put it
on that list */
*packages = alpm_list_add(*packages, pkg);
_alpm_log(handle, ALPM_LOG_DEBUG, "started resolving dependencies\n");
targ = alpm_list_add(NULL, pkg);
deps = alpm_checkdeps(handle, localpkgs, rem, targ, 0);
alpm_list_free(targ);
targ = NULL;
for(j = deps; j; j = j->next) {
alpm_depmissing_t *miss = j->data;
alpm_depend_t *missdep = miss->depend;
/* check if one of the packages in the [*packages] list already satisfies
* this dependency */
if(find_dep_satisfier(*packages, missdep)) {
alpm_depmissing_free(miss);
continue;
}
/* check if one of the packages in the [preferred] list already satisfies
* this dependency */
alpm_pkg_t *spkg = find_dep_satisfier(preferred, missdep);
if(!spkg) {
/* find a satisfier package in the given repositories */
spkg = resolvedep(handle, missdep, handle->dbs_sync, *packages, 0);
}
if(spkg && _alpm_resolvedeps(handle, localpkgs, spkg, preferred, packages, rem, data) == 0) {
_alpm_log(handle, ALPM_LOG_DEBUG,
"pulling dependency %s (needed by %s)\n",
spkg->name, pkg->name);
alpm_depmissing_free(miss);
} else if(resolvedep(handle, missdep, (targ = alpm_list_add(NULL, handle->db_local)), rem, 0)) {
alpm_depmissing_free(miss);
} else {
handle->pm_errno = ALPM_ERR_UNSATISFIED_DEPS;
char *missdepstring = alpm_dep_compute_string(missdep);
_alpm_log(handle, ALPM_LOG_WARNING,
_("cannot resolve \"%s\", a dependency of \"%s\"\n"),
missdepstring, pkg->name);
free(missdepstring);
if(data) {
*data = alpm_list_add(*data, miss);
}
ret = -1;
}
alpm_list_free(targ);
targ = NULL;
}
alpm_list_free(deps);
if(ret != 0) {
alpm_list_free(*packages);
*packages = packages_copy;
} else {
alpm_list_free(packages_copy);
}
_alpm_log(handle, ALPM_LOG_DEBUG, "finished resolving dependencies\n");
return ret;
}
char SYMEXPORT *alpm_dep_compute_string(const alpm_depend_t *dep)
{
const char *name, *opr, *ver, *desc_delim, *desc;
char *str;
size_t len;
ASSERT(dep != NULL, return NULL);
if(dep->name) {
name = dep->name;
} else {
name = "";
}
switch(dep->mod) {
case ALPM_DEP_MOD_ANY:
opr = "";
break;
case ALPM_DEP_MOD_GE:
opr = ">=";
break;
case ALPM_DEP_MOD_LE:
opr = "<=";
break;
case ALPM_DEP_MOD_EQ:
opr = "=";
break;
case ALPM_DEP_MOD_LT:
opr = "<";
break;
case ALPM_DEP_MOD_GT:
opr = ">";
break;
default:
opr = "";
break;
}
if(dep->mod != ALPM_DEP_MOD_ANY && dep->version) {
ver = dep->version;
} else {
ver = "";
}
if(dep->desc) {
desc_delim = ": ";
desc = dep->desc;
} else {
desc_delim = "";
desc = "";
}
/* we can always compute len and print the string like this because opr
* and ver will be empty when ALPM_DEP_MOD_ANY is the depend type. the
* reassignments above also ensure we do not do a strlen(NULL). */
len = strlen(name) + strlen(opr) + strlen(ver)
+ strlen(desc_delim) + strlen(desc) + 1;
MALLOC(str, len, return NULL);
snprintf(str, len, "%s%s%s%s%s", name, opr, ver, desc_delim, desc);
return str;
}

View file

@ -1,41 +0,0 @@
/*
* deps.h
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2006 by Miklos Vajna <vmiklos@frugalware.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, see <http://www.gnu.org/licenses/>.
*/
#ifndef ALPM_DEPS_H
#define ALPM_DEPS_H
#include "db.h"
#include "sync.h"
#include "package.h"
#include "alpm.h"
alpm_depend_t *_alpm_dep_dup(const alpm_depend_t *dep);
alpm_list_t *_alpm_sortbydeps(alpm_handle_t *handle,
alpm_list_t *targets, alpm_list_t *ignore, int reverse);
int _alpm_recursedeps(alpm_db_t *db, alpm_list_t **targs, int include_explicit);
int _alpm_resolvedeps(alpm_handle_t *handle, alpm_list_t *localpkgs, alpm_pkg_t *pkg,
alpm_list_t *preferred, alpm_list_t **packages, alpm_list_t *remove,
alpm_list_t **data);
int _alpm_depcmp_literal(alpm_pkg_t *pkg, alpm_depend_t *dep);
int _alpm_depcmp_provides(alpm_depend_t *dep, alpm_list_t *provisions);
int _alpm_depcmp(alpm_pkg_t *pkg, alpm_depend_t *dep);
#endif /* ALPM_DEPS_H */

View file

@ -1,514 +0,0 @@
/*
* diskspace.c
*
* Copyright (c) 2010-2025 Pacman Development Team <pacman-dev@lists.archlinux.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, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <errno.h>
#if defined(HAVE_MNTENT_H)
#include <mntent.h>
#endif
#if defined(HAVE_SYS_MNTTAB_H)
#include <sys/mnttab.h>
#endif
#if defined(HAVE_SYS_STATVFS_H)
#include <sys/statvfs.h>
#endif
#if defined(HAVE_SYS_PARAM_H)
#include <sys/param.h>
#endif
#if defined(HAVE_SYS_MOUNT_H)
#include <sys/mount.h>
#endif
#if defined(HAVE_SYS_UCRED_H)
#include <sys/ucred.h>
#endif
#if defined(HAVE_SYS_TYPES_H)
#include <sys/types.h>
#endif
/* libalpm */
#include "diskspace.h"
#include "alpm_list.h"
#include "util.h"
#include "log.h"
#include "trans.h"
#include "handle.h"
static int mount_point_cmp(const void *p1, const void *p2)
{
const alpm_mountpoint_t *mp1 = p1;
const alpm_mountpoint_t *mp2 = p2;
/* the negation will sort all mountpoints before their parent */
return -strcmp(mp1->mount_dir, mp2->mount_dir);
}
static void mount_point_list_free(alpm_list_t *mount_points)
{
alpm_list_t *i;
for(i = mount_points; i; i = i->next) {
alpm_mountpoint_t *data = i->data;
FREE(data->mount_dir);
}
FREELIST(mount_points);
}
static int mount_point_load_fsinfo(alpm_handle_t *handle, alpm_mountpoint_t *mountpoint)
{
#if defined(HAVE_GETMNTENT)
/* grab the filesystem usage */
if(statvfs(mountpoint->mount_dir, &(mountpoint->fsp)) != 0) {
_alpm_log(handle, ALPM_LOG_WARNING,
_("could not get filesystem information for %s: %s\n"),
mountpoint->mount_dir, strerror(errno));
mountpoint->fsinfo_loaded = MOUNT_FSINFO_FAIL;
return -1;
}
_alpm_log(handle, ALPM_LOG_DEBUG, "loading fsinfo for %s\n", mountpoint->mount_dir);
mountpoint->read_only = mountpoint->fsp.f_flag & ST_RDONLY;
mountpoint->fsinfo_loaded = MOUNT_FSINFO_LOADED;
#else
(void)handle;
(void)mountpoint;
#endif
return 0;
}
static alpm_list_t *mount_point_list(alpm_handle_t *handle)
{
alpm_list_t *mount_points = NULL, *ptr;
alpm_mountpoint_t *mp;
#if defined(HAVE_GETMNTENT) && defined(HAVE_MNTENT_H)
/* Linux */
struct mntent *mnt;
FILE *fp;
fp = setmntent(MOUNTED, "r");
if(fp == NULL) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not open file: %s: %s\n"),
MOUNTED, strerror(errno));
return NULL;
}
while((mnt = getmntent(fp))) {
if(mnt->mnt_dir == NULL) {
continue;
}
CALLOC(mp, 1, sizeof(alpm_mountpoint_t), RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
STRDUP(mp->mount_dir, mnt->mnt_dir, free(mp); RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
mp->mount_dir_len = strlen(mp->mount_dir);
mount_points = alpm_list_add(mount_points, mp);
}
endmntent(fp);
#elif defined(HAVE_GETMNTENT) && defined(HAVE_MNTTAB_H)
/* Solaris, Illumos */
struct mnttab mnt;
FILE *fp;
int ret;
fp = fopen("/etc/mnttab", "r");
if(fp == NULL) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"),
"/etc/mnttab", strerror(errno));
return NULL;
}
while((ret = getmntent(fp, &mnt)) == 0) {
if(mnt->mnt_mountp == NULL) {
continue;
}
CALLOC(mp, 1, sizeof(alpm_mountpoint_t), RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
STRDUP(mp->mount_dir, mnt->mnt_mountp, free(mp); RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
mp->mount_dir_len = strlen(mp->mount_dir);
mount_points = alpm_list_add(mount_points, mp);
}
/* -1 == EOF */
if(ret != -1) {
_alpm_log(handle, ALPM_LOG_WARNING,
_("could not get filesystem information\n"));
}
fclose(fp);
#elif defined(HAVE_GETMNTINFO)
/* FreeBSD (statfs), NetBSD (statvfs), OpenBSD (statfs), OS X (statfs) */
int entries;
FSSTATSTYPE *fsp;
entries = getmntinfo(&fsp, MNT_NOWAIT);
if(entries < 0) {
_alpm_log(handle, ALPM_LOG_ERROR,
_("could not get filesystem information\n"));
return NULL;
}
for(; entries-- > 0; fsp++) {
if(fsp->f_mntonname == NULL) {
continue;
}
CALLOC(mp, 1, sizeof(alpm_mountpoint_t), RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
STRDUP(mp->mount_dir, fsp->f_mntonname, free(mp); RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
mp->mount_dir_len = strlen(mp->mount_dir);
memcpy(&(mp->fsp), fsp, sizeof(FSSTATSTYPE));
#if defined(HAVE_GETMNTINFO_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_FLAG)
mp->read_only = fsp->f_flag & ST_RDONLY;
#elif defined(HAVE_GETMNTINFO_STATFS) && defined(HAVE_STRUCT_STATFS_F_FLAGS)
mp->read_only = fsp->f_flags & MNT_RDONLY;
#endif
/* we don't support lazy loading on this platform */
mp->fsinfo_loaded = MOUNT_FSINFO_LOADED;
mount_points = alpm_list_add(mount_points, mp);
}
#endif
mount_points = alpm_list_msort(mount_points, alpm_list_count(mount_points),
mount_point_cmp);
for(ptr = mount_points; ptr != NULL; ptr = ptr->next) {
mp = ptr->data;
_alpm_log(handle, ALPM_LOG_DEBUG, "discovered mountpoint: %s\n", mp->mount_dir);
}
return mount_points;
}
static alpm_mountpoint_t *match_mount_point(const alpm_list_t *mount_points,
const char *real_path)
{
const alpm_list_t *mp;
for(mp = mount_points; mp != NULL; mp = mp->next) {
alpm_mountpoint_t *data = mp->data;
/* first, check if the prefix matches */
if(strncmp(data->mount_dir, real_path, data->mount_dir_len) == 0) {
/* now, the hard work- a file like '/etc/myconfig' shouldn't map to a
* mountpoint '/e', but only '/etc'. If the mountpoint ends in a trailing
* slash, we know we didn't have a mismatch, otherwise we have to do some
* more sanity checks. */
if(data->mount_dir[data->mount_dir_len - 1] == '/') {
return data;
} else if(strlen(real_path) >= data->mount_dir_len) {
const char next = real_path[data->mount_dir_len];
if(next == '/' || next == '\0') {
return data;
}
}
}
}
/* should not get here... */
return NULL;
}
static int calculate_removed_size(alpm_handle_t *handle,
const alpm_list_t *mount_points, alpm_pkg_t *pkg)
{
size_t i;
alpm_filelist_t *filelist = alpm_pkg_get_files(pkg);
if(!filelist->count) {
return 0;
}
for(i = 0; i < filelist->count; i++) {
const alpm_file_t *file = filelist->files + i;
alpm_mountpoint_t *mp;
struct stat st;
char path[PATH_MAX];
blkcnt_t remove_size;
const char *filename = file->name;
snprintf(path, PATH_MAX, "%s%s", handle->root, filename);
if(llstat(path, &st) == -1) {
if(alpm_option_match_noextract(handle, filename)) {
_alpm_log(handle, ALPM_LOG_WARNING,
_("could not get file information for %s\n"), filename);
}
continue;
}
/* skip directories and symlinks to be consistent with libarchive that
* reports them to be zero size */
if(S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode)) {
continue;
}
mp = match_mount_point(mount_points, path);
if(mp == NULL) {
_alpm_log(handle, ALPM_LOG_WARNING,
_("could not determine mount point for file %s\n"), filename);
continue;
}
/* don't check a mount that we know we can't stat */
if(mp && mp->fsinfo_loaded == MOUNT_FSINFO_FAIL) {
continue;
}
/* lazy load filesystem info */
if(mp->fsinfo_loaded == MOUNT_FSINFO_UNLOADED) {
if(mount_point_load_fsinfo(handle, mp) < 0) {
continue;
}
}
/* the addition of (divisor - 1) performs ceil() with integer division */
remove_size = (st.st_size + mp->fsp.f_bsize - 1) / mp->fsp.f_bsize;
mp->blocks_needed -= remove_size;
mp->used |= USED_REMOVE;
}
return 0;
}
static int calculate_installed_size(alpm_handle_t *handle,
const alpm_list_t *mount_points, alpm_pkg_t *pkg)
{
size_t i;
alpm_filelist_t *filelist = alpm_pkg_get_files(pkg);
if(!filelist->count) {
return 0;
}
for(i = 0; i < filelist->count; i++) {
const alpm_file_t *file = filelist->files + i;
alpm_mountpoint_t *mp;
char path[PATH_MAX];
blkcnt_t install_size;
const char *filename = file->name;
/* libarchive reports these as zero size anyways */
/* NOTE: if we do start accounting for directory size, a dir matching a
* mountpoint needs to be attributed to the parent, not the mountpoint. */
if(S_ISDIR(file->mode) || S_ISLNK(file->mode)) {
continue;
}
/* approximate space requirements for db entries */
if(filename[0] == '.') {
filename = handle->dbpath;
}
snprintf(path, PATH_MAX, "%s%s", handle->root, filename);
mp = match_mount_point(mount_points, path);
if(mp == NULL) {
_alpm_log(handle, ALPM_LOG_WARNING,
_("could not determine mount point for file %s\n"), filename);
continue;
}
/* don't check a mount that we know we can't stat */
if(mp && mp->fsinfo_loaded == MOUNT_FSINFO_FAIL) {
continue;
}
/* lazy load filesystem info */
if(mp->fsinfo_loaded == MOUNT_FSINFO_UNLOADED) {
if(mount_point_load_fsinfo(handle, mp) < 0) {
continue;
}
}
/* the addition of (divisor - 1) performs ceil() with integer division */
install_size = (file->size + mp->fsp.f_bsize - 1) / mp->fsp.f_bsize;
mp->blocks_needed += install_size;
mp->used |= USED_INSTALL;
}
return 0;
}
static int check_mountpoint(alpm_handle_t *handle, alpm_mountpoint_t *mp)
{
/* cushion is roughly min(5% capacity, 20MiB) */
fsblkcnt_t fivepc = (mp->fsp.f_blocks / 20) + 1;
fsblkcnt_t twentymb = (20 * 1024 * 1024 / mp->fsp.f_bsize) + 1;
fsblkcnt_t cushion = fivepc < twentymb ? fivepc : twentymb;
blkcnt_t needed = mp->max_blocks_needed + cushion;
_alpm_log(handle, ALPM_LOG_DEBUG,
"partition %s, needed %jd, cushion %ju, free %ju\n",
mp->mount_dir, (intmax_t)mp->max_blocks_needed,
(uintmax_t)cushion, (uintmax_t)mp->fsp.f_bavail);
if(needed >= 0 && (fsblkcnt_t)needed > mp->fsp.f_bavail) {
_alpm_log(handle, ALPM_LOG_ERROR,
_("Partition %s too full: %jd blocks needed, %ju blocks free\n"),
mp->mount_dir, (intmax_t)needed, (uintmax_t)mp->fsp.f_bavail);
return 1;
}
return 0;
}
int _alpm_check_downloadspace(alpm_handle_t *handle, const char *cachedir,
size_t num_files, const off_t *file_sizes)
{
alpm_list_t *mount_points;
alpm_mountpoint_t *cachedir_mp;
char resolved_cachedir[PATH_MAX];
size_t j;
int error = 0;
/* resolve the cachedir path to ensure we check the right mountpoint. We
* handle failures silently, and continue to use the possibly unresolved
* path. */
if(realpath(cachedir, resolved_cachedir) != NULL) {
cachedir = resolved_cachedir;
}
mount_points = mount_point_list(handle);
if(mount_points == NULL) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not determine filesystem mount points\n"));
return -1;
}
cachedir_mp = match_mount_point(mount_points, cachedir);
if(cachedir_mp == NULL) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not determine cachedir mount point %s\n"),
cachedir);
error = 1;
goto finish;
}
if(cachedir_mp->fsinfo_loaded == MOUNT_FSINFO_UNLOADED) {
if(mount_point_load_fsinfo(handle, cachedir_mp)) {
error = 1;
goto finish;
}
}
/* there's no need to check for a R/O mounted filesystem here, as
* _alpm_filecache_setup will never give us a non-writable directory */
/* round up the size of each file to the nearest block and accumulate */
for(j = 0; j < num_files; j++) {
cachedir_mp->max_blocks_needed += (file_sizes[j] + cachedir_mp->fsp.f_bsize + 1) /
cachedir_mp->fsp.f_bsize;
}
if(check_mountpoint(handle, cachedir_mp)) {
error = 1;
}
finish:
mount_point_list_free(mount_points);
if(error) {
RET_ERR(handle, ALPM_ERR_DISK_SPACE, -1);
}
return 0;
}
int _alpm_check_diskspace(alpm_handle_t *handle)
{
alpm_list_t *mount_points, *i;
alpm_mountpoint_t *root_mp;
size_t replaces = 0, current = 0, numtargs;
int error = 0;
alpm_list_t *targ;
alpm_trans_t *trans = handle->trans;
numtargs = alpm_list_count(trans->add);
mount_points = mount_point_list(handle);
if(mount_points == NULL) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not determine filesystem mount points\n"));
return -1;
}
root_mp = match_mount_point(mount_points, handle->root);
if(root_mp == NULL) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not determine root mount point %s\n"),
handle->root);
error = 1;
goto finish;
}
replaces = alpm_list_count(trans->remove);
if(replaces) {
numtargs += replaces;
for(targ = trans->remove; targ; targ = targ->next, current++) {
alpm_pkg_t *local_pkg;
int percent = (current * 100) / numtargs;
PROGRESS(handle, ALPM_PROGRESS_DISKSPACE_START, "", percent,
numtargs, current);
local_pkg = targ->data;
calculate_removed_size(handle, mount_points, local_pkg);
}
}
for(targ = trans->add; targ; targ = targ->next, current++) {
alpm_pkg_t *pkg, *local_pkg;
int percent = (current * 100) / numtargs;
PROGRESS(handle, ALPM_PROGRESS_DISKSPACE_START, "", percent,
numtargs, current);
pkg = targ->data;
/* is this package already installed? */
local_pkg = _alpm_db_get_pkgfromcache(handle->db_local, pkg->name);
if(local_pkg) {
calculate_removed_size(handle, mount_points, local_pkg);
}
calculate_installed_size(handle, mount_points, pkg);
for(i = mount_points; i; i = i->next) {
alpm_mountpoint_t *data = i->data;
if(data->blocks_needed > data->max_blocks_needed) {
data->max_blocks_needed = data->blocks_needed;
}
}
}
PROGRESS(handle, ALPM_PROGRESS_DISKSPACE_START, "", 100,
numtargs, current);
for(i = mount_points; i; i = i->next) {
alpm_mountpoint_t *data = i->data;
if(data->used && data->read_only) {
_alpm_log(handle, ALPM_LOG_ERROR, _("Partition %s is mounted read only\n"),
data->mount_dir);
error = 1;
} else if(data->used & USED_INSTALL && check_mountpoint(handle, data)) {
error = 1;
}
}
finish:
mount_point_list_free(mount_points);
if(error) {
RET_ERR(handle, ALPM_ERR_DISK_SPACE, -1);
}
return 0;
}

View file

@ -1,63 +0,0 @@
/*
* diskspace.h
*
* Copyright (c) 2010-2025 Pacman Development Team <pacman-dev@lists.archlinux.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, see <http://www.gnu.org/licenses/>.
*/
#ifndef ALPM_DISKSPACE_H
#define ALPM_DISKSPACE_H
#if defined(HAVE_SYS_MOUNT_H)
#include <sys/mount.h>
#endif
#if defined(HAVE_SYS_STATVFS_H)
#include <sys/statvfs.h>
#endif
#if defined(HAVE_SYS_TYPES_H)
#include <sys/types.h>
#endif
#include "alpm.h"
enum mount_used_level {
USED_REMOVE = 1,
USED_INSTALL = (1 << 1),
};
enum mount_fsinfo {
MOUNT_FSINFO_UNLOADED = 0,
MOUNT_FSINFO_LOADED,
MOUNT_FSINFO_FAIL,
};
typedef struct _alpm_mountpoint_t {
/* mount point information */
char *mount_dir;
size_t mount_dir_len;
/* storage for additional disk usage calculations */
blkcnt_t blocks_needed;
blkcnt_t max_blocks_needed;
enum mount_used_level used;
int read_only;
enum mount_fsinfo fsinfo_loaded;
FSSTATSTYPE fsp;
} alpm_mountpoint_t;
int _alpm_check_diskspace(alpm_handle_t *handle);
int _alpm_check_downloadspace(alpm_handle_t *handle, const char *cachedir,
size_t num_files, const off_t *file_sizes);
#endif /* ALPM_DISKSPACE_H */

File diff suppressed because it is too large Load diff

View file

@ -1,72 +0,0 @@
/*
* dload.h
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef ALPM_DLOAD_H
#define ALPM_DLOAD_H
#include "alpm_list.h"
#include "alpm.h"
struct dload_payload {
alpm_handle_t *handle;
const char *tempfile_openmode;
/* name of the remote file */
char *remote_name;
/* temporary file name, to which the payload is downloaded */
char *tempfile_name;
/* name to which the downloaded file will be renamed */
char *destfile_name;
/* client has to provide either
* 1) fileurl - full URL to the file
* 2) pair of (servers, filepath), in this case ALPM iterates over the
* server list and tries to download "$server/$filepath"
*/
char *fileurl;
char *filepath; /* download URL path */
alpm_list_t *cache_servers;
alpm_list_t *servers;
long respcode;
/* the mtime of the existing version of this file, if there is one */
long mtime_existing_file;
off_t initial_size;
off_t max_size;
off_t prevprogress;
int force;
int allow_resume;
int errors_ok;
int unlink_on_fail;
int download_signature; /* specifies if an accompanion *.sig file need to be downloaded*/
int signature_optional; /* *.sig file is optional */
#ifdef HAVE_LIBCURL
CURL *curl;
char error_buffer[CURL_ERROR_SIZE];
int signature; /* specifies if this payload is for a signature file */
int request_errors_ok; /* per-request errors-ok */
#endif
FILE *localf; /* temp download file */
};
void _alpm_dload_payload_reset(struct dload_payload *payload);
int _alpm_download(alpm_handle_t *handle,
alpm_list_t *payloads /* struct dload_payload */,
const char *localpath,
const char *temporary_localpath);
#endif /* ALPM_DLOAD_H */

View file

@ -1,164 +0,0 @@
/*
* error.c
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 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, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_LIBCURL
#include <curl/curl.h>
#endif
/* libalpm */
#include "util.h"
#include "alpm.h"
#include "handle.h"
alpm_errno_t SYMEXPORT alpm_errno(alpm_handle_t *handle)
{
return handle->pm_errno;
}
const char SYMEXPORT *alpm_strerror(alpm_errno_t err)
{
switch(err) {
/* System */
case ALPM_ERR_MEMORY:
return _("out of memory!");
case ALPM_ERR_SYSTEM:
return _("unexpected system error");
case ALPM_ERR_BADPERMS:
return _("permission denied");
case ALPM_ERR_NOT_A_FILE:
return _("could not find or read file");
case ALPM_ERR_NOT_A_DIR:
return _("could not find or read directory");
case ALPM_ERR_WRONG_ARGS:
return _("wrong or NULL argument passed");
case ALPM_ERR_DISK_SPACE:
return _("not enough free disk space");
/* Interface */
case ALPM_ERR_HANDLE_NULL:
return _("library not initialized");
case ALPM_ERR_HANDLE_NOT_NULL:
return _("library already initialized");
case ALPM_ERR_HANDLE_LOCK:
return _("unable to lock database");
/* Databases */
case ALPM_ERR_DB_OPEN:
return _("could not open database");
case ALPM_ERR_DB_CREATE:
return _("could not create database");
case ALPM_ERR_DB_NULL:
return _("database not initialized");
case ALPM_ERR_DB_NOT_NULL:
return _("database already registered");
case ALPM_ERR_DB_NOT_FOUND:
return _("could not find database");
case ALPM_ERR_DB_INVALID:
return _("invalid or corrupted database");
case ALPM_ERR_DB_INVALID_SIG:
return _("invalid or corrupted database (PGP signature)");
case ALPM_ERR_DB_VERSION:
return _("database is incorrect version");
case ALPM_ERR_DB_WRITE:
return _("could not update database");
case ALPM_ERR_DB_REMOVE:
return _("could not remove database entry");
/* Servers */
case ALPM_ERR_SERVER_BAD_URL:
return _("invalid url for server");
case ALPM_ERR_SERVER_NONE:
return _("no servers configured for repository");
/* Transactions */
case ALPM_ERR_TRANS_NOT_NULL:
return _("transaction already initialized");
case ALPM_ERR_TRANS_NULL:
return _("transaction not initialized");
case ALPM_ERR_TRANS_DUP_TARGET:
return _("duplicate target");
case ALPM_ERR_TRANS_DUP_FILENAME:
return _("duplicate filename");
case ALPM_ERR_TRANS_NOT_INITIALIZED:
return _("transaction not initialized");
case ALPM_ERR_TRANS_NOT_PREPARED:
return _("transaction not prepared");
case ALPM_ERR_TRANS_ABORT:
return _("transaction aborted");
case ALPM_ERR_TRANS_TYPE:
return _("operation not compatible with the transaction type");
case ALPM_ERR_TRANS_NOT_LOCKED:
return _("transaction commit attempt when database is not locked");
case ALPM_ERR_TRANS_HOOK_FAILED:
return _("failed to run transaction hooks");
/* Packages */
case ALPM_ERR_PKG_NOT_FOUND:
return _("could not find or read package");
case ALPM_ERR_PKG_IGNORED:
return _("operation cancelled due to ignorepkg");
case ALPM_ERR_PKG_INVALID:
return _("invalid or corrupted package");
case ALPM_ERR_PKG_INVALID_CHECKSUM:
return _("invalid or corrupted package (checksum)");
case ALPM_ERR_PKG_INVALID_SIG:
return _("invalid or corrupted package (PGP signature)");
case ALPM_ERR_PKG_MISSING_SIG:
return _("package missing required signature");
case ALPM_ERR_PKG_OPEN:
return _("cannot open package file");
case ALPM_ERR_PKG_CANT_REMOVE:
return _("cannot remove all files for package");
case ALPM_ERR_PKG_INVALID_NAME:
return _("package filename is not valid");
case ALPM_ERR_PKG_INVALID_ARCH:
return _("package architecture is not valid");
/* Signatures */
case ALPM_ERR_SIG_MISSING:
return _("missing PGP signature");
case ALPM_ERR_SIG_INVALID:
return _("invalid PGP signature");
/* Dependencies */
case ALPM_ERR_UNSATISFIED_DEPS:
return _("could not satisfy dependencies");
case ALPM_ERR_CONFLICTING_DEPS:
return _("conflicting dependencies");
case ALPM_ERR_FILE_CONFLICTS:
return _("conflicting files");
/* Miscellaneous */
case ALPM_ERR_RETRIEVE:
return _("failed to retrieve some files");
case ALPM_ERR_INVALID_REGEX:
return _("invalid regular expression");
/* Errors from external libraries- our own wrapper error */
case ALPM_ERR_LIBARCHIVE:
/* it would be nice to use archive_error_string() here, but that
* requires the archive struct, so we can't. Just use a generic
* error string instead. */
return _("libarchive error");
case ALPM_ERR_LIBCURL:
return _("download library error");
case ALPM_ERR_GPGME:
return _("gpgme error");
case ALPM_ERR_EXTERNAL_DOWNLOAD:
return _("error invoking external downloader");
/* Missing compile-time features */
case ALPM_ERR_MISSING_CAPABILITY_SIGNATURES:
return _("compiled without signature support");
/* Unknown error! */
default:
return _("unexpected error");
}
}

View file

@ -1,147 +0,0 @@
/*
* filelist.c
*
* Copyright (c) 2012-2025 Pacman Development Team <pacman-dev@lists.archlinux.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, see <http://www.gnu.org/licenses/>.
*/
#include <limits.h>
#include <string.h>
#include <sys/stat.h>
/* libalpm */
#include "filelist.h"
#include "util.h"
/* Returns the difference of the provided two lists of files.
* Pre-condition: both lists are sorted!
* When done, free the list but NOT the contained data.
*/
alpm_list_t *_alpm_filelist_difference(alpm_filelist_t *filesA,
alpm_filelist_t *filesB)
{
alpm_list_t *ret = NULL;
size_t ctrA = 0, ctrB = 0;
while(ctrA < filesA->count && ctrB < filesB->count) {
char *strA = filesA->files[ctrA].name;
char *strB = filesB->files[ctrB].name;
int cmp = strcmp(strA, strB);
if(cmp < 0) {
/* item only in filesA, qualifies as a difference */
ret = alpm_list_add(ret, strA);
ctrA++;
} else if(cmp > 0) {
ctrB++;
} else {
ctrA++;
ctrB++;
}
}
/* ensure we have completely emptied pA */
while(ctrA < filesA->count) {
ret = alpm_list_add(ret, filesA->files[ctrA].name);
ctrA++;
}
return ret;
}
static int _alpm_filelist_pathcmp(const char *p1, const char *p2)
{
while(*p1 && *p1 == *p2) {
p1++;
p2++;
}
/* skip trailing '/' */
if(*p1 == '\0' && *p2 == '/') {
p2++;
} else if(*p2 == '\0' && *p1 == '/') {
p1++;
}
return *p1 - *p2;
}
/* Returns the intersection of the provided two lists of files.
* Pre-condition: both lists are sorted!
* When done, free the list but NOT the contained data.
*/
alpm_list_t *_alpm_filelist_intersection(alpm_filelist_t *filesA,
alpm_filelist_t *filesB)
{
alpm_list_t *ret = NULL;
size_t ctrA = 0, ctrB = 0;
alpm_file_t *arrA = filesA->files, *arrB = filesB->files;
while(ctrA < filesA->count && ctrB < filesB->count) {
const char *strA = arrA[ctrA].name, *strB = arrB[ctrB].name;
int cmp = _alpm_filelist_pathcmp(strA, strB);
if(cmp < 0) {
ctrA++;
} else if(cmp > 0) {
ctrB++;
} else {
/* when not directories, item in both qualifies as an intersect */
if(strA[strlen(strA) - 1] != '/' || strB[strlen(strB) - 1] != '/') {
ret = alpm_list_add(ret, arrA[ctrA].name);
}
ctrA++;
ctrB++;
}
}
return ret;
}
/* Helper function for comparing files list entries
*/
static int _alpm_files_cmp(const void *f1, const void *f2)
{
const alpm_file_t *file1 = f1;
const alpm_file_t *file2 = f2;
return strcmp(file1->name, file2->name);
}
alpm_file_t SYMEXPORT *alpm_filelist_contains(const alpm_filelist_t *filelist,
const char *path)
{
alpm_file_t key;
if(!filelist || filelist->count == 0) {
return NULL;
}
key.name = (char *)path;
return bsearch(&key, filelist->files, filelist->count,
sizeof(alpm_file_t), _alpm_files_cmp);
}
void _alpm_filelist_sort(alpm_filelist_t *filelist)
{
size_t i;
for(i = 1; i < filelist->count; i++) {
if(strcmp(filelist->files[i - 1].name, filelist->files[i].name) > 0) {
/* filelist is not pre-sorted */
qsort(filelist->files, filelist->count,
sizeof(alpm_file_t), _alpm_files_cmp);
return;
}
}
}

View file

@ -1,32 +0,0 @@
/*
* filelist.h
*
* Copyright (c) 2012-2025 Pacman Development Team <pacman-dev@lists.archlinux.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, see <http://www.gnu.org/licenses/>.
*/
#ifndef ALPM_FILELIST_H
#define ALPM_FILELIST_H
#include "alpm.h"
alpm_list_t *_alpm_filelist_difference(alpm_filelist_t *filesA,
alpm_filelist_t *filesB);
alpm_list_t *_alpm_filelist_intersection(alpm_filelist_t *filesA,
alpm_filelist_t *filesB);
void _alpm_filelist_sort(alpm_filelist_t *filelist);
#endif /* ALPM_FILELIST_H */

View file

@ -1,38 +0,0 @@
/*
* graph.c - helpful graph structure and setup/teardown methods
*
* Copyright (c) 2007-2025 Pacman Development Team <pacman-dev@lists.archlinux.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, see <http://www.gnu.org/licenses/>.
*/
#include "graph.h"
#include "util.h"
#include "log.h"
alpm_graph_t *_alpm_graph_new(void)
{
alpm_graph_t *graph = NULL;
CALLOC(graph, 1, sizeof(alpm_graph_t), return NULL);
return graph;
}
void _alpm_graph_free(void *data)
{
ASSERT(data != NULL, return);
alpm_graph_t *graph = data;
alpm_list_free(graph->children);
free(graph);
}

View file

@ -1,44 +0,0 @@
/*
* graph.h - helpful graph structure and setup/teardown methods
*
* Copyright (c) 2007-2025 Pacman Development Team <pacman-dev@lists.archlinux.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, see <http://www.gnu.org/licenses/>.
*/
#ifndef ALPM_GRAPH_H
#define ALPM_GRAPH_H
#include <sys/types.h> /* off_t */
#include "alpm_list.h"
enum _alpm_graph_vertex_state {
ALPM_GRAPH_STATE_UNPROCESSED,
ALPM_GRAPH_STATE_PROCESSING,
ALPM_GRAPH_STATE_PROCESSED
};
typedef struct _alpm_graph_t {
void *data;
struct _alpm_graph_t *parent; /* where did we come from? */
alpm_list_t *children;
alpm_list_t *iterator; /* used for DFS without recursion */
off_t weight; /* weight of the node */
enum _alpm_graph_vertex_state state;
} alpm_graph_t;
alpm_graph_t *_alpm_graph_new(void);
void _alpm_graph_free(void *data);
#endif /* ALPM_GRAPH_H */

View file

@ -1,51 +0,0 @@
/*
* group.c
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
/* libalpm */
#include "group.h"
#include "alpm_list.h"
#include "util.h"
#include "log.h"
#include "alpm.h"
alpm_group_t *_alpm_group_new(const char *name)
{
alpm_group_t *grp;
CALLOC(grp, 1, sizeof(alpm_group_t), return NULL);
STRDUP(grp->name, name, free(grp); return NULL);
return grp;
}
void _alpm_group_free(alpm_group_t *grp)
{
if(grp == NULL) {
return;
}
FREE(grp->name);
/* do NOT free the contents of the list, just the nodes */
alpm_list_free(grp->packages);
FREE(grp);
}

View file

@ -1,973 +0,0 @@
/*
* handle.c
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.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, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <syslog.h>
#include <sys/stat.h>
#include <fcntl.h>
/* libalpm */
#include "handle.h"
#include "alpm_list.h"
#include "util.h"
#include "log.h"
#include "trans.h"
#include "alpm.h"
#include "deps.h"
alpm_handle_t *_alpm_handle_new(void)
{
alpm_handle_t *handle;
CALLOC(handle, 1, sizeof(alpm_handle_t), return NULL);
handle->lockfd = -1;
return handle;
}
/* free all in-memory resources */
void _alpm_handle_free(alpm_handle_t *handle)
{
alpm_list_t *i;
alpm_db_t *db;
if(handle == NULL) {
return;
}
/* close local database */
if((db = handle->db_local)) {
db->ops->unregister(db);
}
/* unregister all sync dbs */
for(i = handle->dbs_sync; i; i = i->next) {
db = i->data;
db->ops->unregister(db);
}
alpm_list_free(handle->dbs_sync);
/* close logfile */
if(handle->logstream) {
fclose(handle->logstream);
handle->logstream = NULL;
}
if(handle->usesyslog) {
handle->usesyslog = 0;
closelog();
}
#ifdef HAVE_LIBGPGME
FREELIST(handle->known_keys);
#endif
#ifdef HAVE_LIBCURL
curl_multi_cleanup(handle->curlm);
curl_global_cleanup();
FREELIST(handle->server_errors);
#endif
/* free memory */
_alpm_trans_free(handle->trans);
FREE(handle->root);
FREE(handle->dbpath);
FREE(handle->dbext);
FREELIST(handle->cachedirs);
FREELIST(handle->hookdirs);
FREE(handle->logfile);
FREE(handle->lockfile);
FREELIST(handle->architectures);
FREE(handle->gpgdir);
FREE(handle->sandboxuser);
FREELIST(handle->noupgrade);
FREELIST(handle->noextract);
FREELIST(handle->ignorepkg);
FREELIST(handle->ignoregroup);
FREELIST(handle->overwrite_files);
alpm_list_free_inner(handle->assumeinstalled, (alpm_list_fn_free)alpm_dep_free);
alpm_list_free(handle->assumeinstalled);
FREE(handle);
}
/** Lock the database */
int _alpm_handle_lock(alpm_handle_t *handle)
{
char *dir, *ptr;
ASSERT(handle->lockfile != NULL, return -1);
ASSERT(handle->lockfd < 0, return 0);
/* create the dir of the lockfile first */
STRDUP(dir, handle->lockfile, return -1);
ptr = strrchr(dir, '/');
if(ptr) {
*ptr = '\0';
}
if(_alpm_makepath(dir)) {
FREE(dir);
return -1;
}
FREE(dir);
do {
handle->lockfd = open(handle->lockfile, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0000);
} while(handle->lockfd == -1 && errno == EINTR);
return (handle->lockfd >= 0 ? 0 : -1);
}
int SYMEXPORT alpm_unlock(alpm_handle_t *handle)
{
ASSERT(handle != NULL, return -1);
ASSERT(handle->lockfile != NULL, return 0);
ASSERT(handle->lockfd >= 0, return 0);
close(handle->lockfd);
handle->lockfd = -1;
if(unlink(handle->lockfile) != 0) {
RET_ERR_ASYNC_SAFE(handle, ALPM_ERR_SYSTEM, -1);
} else {
return 0;
}
}
int _alpm_handle_unlock(alpm_handle_t *handle)
{
if(alpm_unlock(handle) != 0) {
if(errno == ENOENT) {
_alpm_log(handle, ALPM_LOG_WARNING,
_("lock file missing %s\n"), handle->lockfile);
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"warning: lock file missing %s\n", handle->lockfile);
return 0;
} else {
_alpm_log(handle, ALPM_LOG_WARNING,
_("could not remove lock file %s\n"), handle->lockfile);
alpm_logaction(handle, ALPM_CALLER_PREFIX,
"warning: could not remove lock file %s\n", handle->lockfile);
return -1;
}
}
return 0;
}
alpm_cb_log SYMEXPORT alpm_option_get_logcb(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->logcb;
}
void SYMEXPORT *alpm_option_get_logcb_ctx(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->logcb_ctx;
}
alpm_cb_download SYMEXPORT alpm_option_get_dlcb(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->dlcb;
}
void SYMEXPORT *alpm_option_get_dlcb_ctx(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->dlcb_ctx;
}
alpm_cb_fetch SYMEXPORT alpm_option_get_fetchcb(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->fetchcb;
}
void SYMEXPORT *alpm_option_get_fetchcb_ctx(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->fetchcb_ctx;
}
alpm_cb_event SYMEXPORT alpm_option_get_eventcb(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->eventcb;
}
void SYMEXPORT *alpm_option_get_eventcb_ctx(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->eventcb_ctx;
}
alpm_cb_question SYMEXPORT alpm_option_get_questioncb(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->questioncb;
}
void SYMEXPORT *alpm_option_get_questioncb_ctx(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->questioncb_ctx;
}
alpm_cb_progress SYMEXPORT alpm_option_get_progresscb(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->progresscb;
}
void SYMEXPORT *alpm_option_get_progresscb_ctx(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->progresscb_ctx;
}
const char SYMEXPORT *alpm_option_get_root(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->root;
}
const char SYMEXPORT *alpm_option_get_dbpath(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->dbpath;
}
alpm_list_t SYMEXPORT *alpm_option_get_hookdirs(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->hookdirs;
}
alpm_list_t SYMEXPORT *alpm_option_get_cachedirs(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->cachedirs;
}
const char SYMEXPORT *alpm_option_get_logfile(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->logfile;
}
const char SYMEXPORT *alpm_option_get_lockfile(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->lockfile;
}
const char SYMEXPORT *alpm_option_get_gpgdir(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->gpgdir;
}
const char SYMEXPORT *alpm_option_get_sandboxuser(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->sandboxuser;
}
int SYMEXPORT alpm_option_get_usesyslog(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return -1);
return handle->usesyslog;
}
alpm_list_t SYMEXPORT *alpm_option_get_noupgrades(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->noupgrade;
}
alpm_list_t SYMEXPORT *alpm_option_get_noextracts(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->noextract;
}
alpm_list_t SYMEXPORT *alpm_option_get_ignorepkgs(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->ignorepkg;
}
alpm_list_t SYMEXPORT *alpm_option_get_ignoregroups(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->ignoregroup;
}
alpm_list_t SYMEXPORT *alpm_option_get_overwrite_files(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->overwrite_files;
}
alpm_list_t SYMEXPORT *alpm_option_get_assumeinstalled(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->assumeinstalled;
}
alpm_list_t SYMEXPORT *alpm_option_get_architectures(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->architectures;
}
int SYMEXPORT alpm_option_get_checkspace(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return -1);
return handle->checkspace;
}
const char SYMEXPORT *alpm_option_get_dbext(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->dbext;
}
int SYMEXPORT alpm_option_get_parallel_downloads(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return -1);
return handle->parallel_downloads;
}
int SYMEXPORT alpm_option_set_logcb(alpm_handle_t *handle, alpm_cb_log cb, void *ctx)
{
CHECK_HANDLE(handle, return -1);
handle->logcb = cb;
handle->logcb_ctx = ctx;
return 0;
}
int SYMEXPORT alpm_option_set_dlcb(alpm_handle_t *handle, alpm_cb_download cb, void *ctx)
{
CHECK_HANDLE(handle, return -1);
handle->dlcb = cb;
handle->dlcb_ctx = ctx;
return 0;
}
int SYMEXPORT alpm_option_set_fetchcb(alpm_handle_t *handle, alpm_cb_fetch cb, void *ctx)
{
CHECK_HANDLE(handle, return -1);
handle->fetchcb = cb;
handle->fetchcb_ctx = ctx;
return 0;
}
int SYMEXPORT alpm_option_set_eventcb(alpm_handle_t *handle, alpm_cb_event cb, void *ctx)
{
CHECK_HANDLE(handle, return -1);
handle->eventcb = cb;
handle->eventcb_ctx = ctx;
return 0;
}
int SYMEXPORT alpm_option_set_questioncb(alpm_handle_t *handle, alpm_cb_question cb, void *ctx)
{
CHECK_HANDLE(handle, return -1);
handle->questioncb = cb;
handle->questioncb_ctx = ctx;
return 0;
}
int SYMEXPORT alpm_option_set_progresscb(alpm_handle_t *handle, alpm_cb_progress cb, void *ctx)
{
CHECK_HANDLE(handle, return -1);
handle->progresscb = cb;
handle->progresscb_ctx = ctx;
return 0;
}
static char *canonicalize_path(const char *path)
{
char *new_path;
size_t len;
/* verify path ends in a '/' */
len = strlen(path);
if(path[len - 1] != '/') {
len += 1;
}
CALLOC(new_path, len + 1, sizeof(char), return NULL);
strcpy(new_path, path);
new_path[len - 1] = '/';
return new_path;
}
alpm_errno_t _alpm_set_directory_option(const char *value,
char **storage, int must_exist)
{
struct stat st;
char real[PATH_MAX];
const char *path;
path = value;
if(!path) {
return ALPM_ERR_WRONG_ARGS;
}
if(must_exist) {
if(stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) {
return ALPM_ERR_NOT_A_DIR;
}
if(!realpath(path, real)) {
return ALPM_ERR_NOT_A_DIR;
}
path = real;
}
if(*storage) {
FREE(*storage);
}
*storage = canonicalize_path(path);
if(!*storage) {
return ALPM_ERR_MEMORY;
}
return 0;
}
int SYMEXPORT alpm_option_add_hookdir(alpm_handle_t *handle, const char *hookdir)
{
char *newhookdir;
CHECK_HANDLE(handle, return -1);
ASSERT(hookdir != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
newhookdir = canonicalize_path(hookdir);
if(!newhookdir) {
RET_ERR(handle, ALPM_ERR_MEMORY, -1);
}
handle->hookdirs = alpm_list_add(handle->hookdirs, newhookdir);
_alpm_log(handle, ALPM_LOG_DEBUG, "option 'hookdir' = %s\n", newhookdir);
return 0;
}
int SYMEXPORT alpm_option_set_hookdirs(alpm_handle_t *handle, alpm_list_t *hookdirs)
{
alpm_list_t *i;
CHECK_HANDLE(handle, return -1);
if(handle->hookdirs) {
FREELIST(handle->hookdirs);
}
for(i = hookdirs; i; i = i->next) {
int ret = alpm_option_add_hookdir(handle, i->data);
if(ret) {
return ret;
}
}
return 0;
}
int SYMEXPORT alpm_option_remove_hookdir(alpm_handle_t *handle, const char *hookdir)
{
char *vdata = NULL;
char *newhookdir;
CHECK_HANDLE(handle, return -1);
ASSERT(hookdir != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
newhookdir = canonicalize_path(hookdir);
if(!newhookdir) {
RET_ERR(handle, ALPM_ERR_MEMORY, -1);
}
handle->hookdirs = alpm_list_remove_str(handle->hookdirs, newhookdir, &vdata);
FREE(newhookdir);
if(vdata != NULL) {
FREE(vdata);
return 1;
}
return 0;
}
int SYMEXPORT alpm_option_add_cachedir(alpm_handle_t *handle, const char *cachedir)
{
char *newcachedir;
CHECK_HANDLE(handle, return -1);
ASSERT(cachedir != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
/* don't stat the cachedir yet, as it may not even be needed. we can
* fail later if it is needed and the path is invalid. */
newcachedir = canonicalize_path(cachedir);
if(!newcachedir) {
RET_ERR(handle, ALPM_ERR_MEMORY, -1);
}
handle->cachedirs = alpm_list_add(handle->cachedirs, newcachedir);
_alpm_log(handle, ALPM_LOG_DEBUG, "option 'cachedir' = %s\n", newcachedir);
return 0;
}
int SYMEXPORT alpm_option_set_cachedirs(alpm_handle_t *handle, alpm_list_t *cachedirs)
{
alpm_list_t *i;
CHECK_HANDLE(handle, return -1);
if(handle->cachedirs) {
FREELIST(handle->cachedirs);
}
for(i = cachedirs; i; i = i->next) {
int ret = alpm_option_add_cachedir(handle, i->data);
if(ret) {
return ret;
}
}
return 0;
}
int SYMEXPORT alpm_option_remove_cachedir(alpm_handle_t *handle, const char *cachedir)
{
char *vdata = NULL;
char *newcachedir;
CHECK_HANDLE(handle, return -1);
ASSERT(cachedir != NULL, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
newcachedir = canonicalize_path(cachedir);
if(!newcachedir) {
RET_ERR(handle, ALPM_ERR_MEMORY, -1);
}
handle->cachedirs = alpm_list_remove_str(handle->cachedirs, newcachedir, &vdata);
FREE(newcachedir);
if(vdata != NULL) {
FREE(vdata);
return 1;
}
return 0;
}
int SYMEXPORT alpm_option_set_logfile(alpm_handle_t *handle, const char *logfile)
{
char *oldlogfile = handle->logfile;
CHECK_HANDLE(handle, return -1);
if(!logfile) {
handle->pm_errno = ALPM_ERR_WRONG_ARGS;
return -1;
}
STRDUP(handle->logfile, logfile, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
/* free the old logfile path string, and close the stream so logaction
* will reopen a new stream on the new logfile */
if(oldlogfile) {
FREE(oldlogfile);
}
if(handle->logstream) {
fclose(handle->logstream);
handle->logstream = NULL;
}
_alpm_log(handle, ALPM_LOG_DEBUG, "option 'logfile' = %s\n", handle->logfile);
return 0;
}
int SYMEXPORT alpm_option_set_gpgdir(alpm_handle_t *handle, const char *gpgdir)
{
int err;
CHECK_HANDLE(handle, return -1);
if((err = _alpm_set_directory_option(gpgdir, &(handle->gpgdir), 0))) {
RET_ERR(handle, err, -1);
}
_alpm_log(handle, ALPM_LOG_DEBUG, "option 'gpgdir' = %s\n", handle->gpgdir);
return 0;
}
int SYMEXPORT alpm_option_set_sandboxuser(alpm_handle_t *handle, const char *sandboxuser)
{
CHECK_HANDLE(handle, return -1);
if(handle->sandboxuser) {
FREE(handle->sandboxuser);
}
STRDUP(handle->sandboxuser, sandboxuser, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
_alpm_log(handle, ALPM_LOG_DEBUG, "option 'sandboxuser' = %s\n", handle->sandboxuser);
return 0;
}
int SYMEXPORT alpm_option_set_usesyslog(alpm_handle_t *handle, int usesyslog)
{
CHECK_HANDLE(handle, return -1);
handle->usesyslog = usesyslog;
return 0;
}
static int _alpm_option_strlist_add(alpm_handle_t *handle, alpm_list_t **list, const char *str)
{
char *dup;
CHECK_HANDLE(handle, return -1);
STRDUP(dup, str, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
*list = alpm_list_add(*list, dup);
return 0;
}
static int _alpm_option_strlist_set(alpm_handle_t *handle, alpm_list_t **list, alpm_list_t *newlist)
{
CHECK_HANDLE(handle, return -1);
FREELIST(*list);
*list = alpm_list_strdup(newlist);
return 0;
}
static int _alpm_option_strlist_rem(alpm_handle_t *handle, alpm_list_t **list, const char *str)
{
char *vdata = NULL;
CHECK_HANDLE(handle, return -1);
*list = alpm_list_remove_str(*list, str, &vdata);
if(vdata != NULL) {
FREE(vdata);
return 1;
}
return 0;
}
int SYMEXPORT alpm_option_add_noupgrade(alpm_handle_t *handle, const char *pkg)
{
return _alpm_option_strlist_add(handle, &(handle->noupgrade), pkg);
}
int SYMEXPORT alpm_option_set_noupgrades(alpm_handle_t *handle, alpm_list_t *noupgrade)
{
return _alpm_option_strlist_set(handle, &(handle->noupgrade), noupgrade);
}
int SYMEXPORT alpm_option_remove_noupgrade(alpm_handle_t *handle, const char *pkg)
{
return _alpm_option_strlist_rem(handle, &(handle->noupgrade), pkg);
}
int SYMEXPORT alpm_option_match_noupgrade(alpm_handle_t *handle, const char *path)
{
return _alpm_fnmatch_patterns(handle->noupgrade, path);
}
int SYMEXPORT alpm_option_add_noextract(alpm_handle_t *handle, const char *path)
{
return _alpm_option_strlist_add(handle, &(handle->noextract), path);
}
int SYMEXPORT alpm_option_set_noextracts(alpm_handle_t *handle, alpm_list_t *noextract)
{
return _alpm_option_strlist_set(handle, &(handle->noextract), noextract);
}
int SYMEXPORT alpm_option_remove_noextract(alpm_handle_t *handle, const char *path)
{
return _alpm_option_strlist_rem(handle, &(handle->noextract), path);
}
int SYMEXPORT alpm_option_match_noextract(alpm_handle_t *handle, const char *path)
{
return _alpm_fnmatch_patterns(handle->noextract, path);
}
int SYMEXPORT alpm_option_add_ignorepkg(alpm_handle_t *handle, const char *pkg)
{
return _alpm_option_strlist_add(handle, &(handle->ignorepkg), pkg);
}
int SYMEXPORT alpm_option_set_ignorepkgs(alpm_handle_t *handle, alpm_list_t *ignorepkgs)
{
return _alpm_option_strlist_set(handle, &(handle->ignorepkg), ignorepkgs);
}
int SYMEXPORT alpm_option_remove_ignorepkg(alpm_handle_t *handle, const char *pkg)
{
return _alpm_option_strlist_rem(handle, &(handle->ignorepkg), pkg);
}
int SYMEXPORT alpm_option_add_ignoregroup(alpm_handle_t *handle, const char *grp)
{
return _alpm_option_strlist_add(handle, &(handle->ignoregroup), grp);
}
int SYMEXPORT alpm_option_set_ignoregroups(alpm_handle_t *handle, alpm_list_t *ignoregrps)
{
return _alpm_option_strlist_set(handle, &(handle->ignoregroup), ignoregrps);
}
int SYMEXPORT alpm_option_remove_ignoregroup(alpm_handle_t *handle, const char *grp)
{
return _alpm_option_strlist_rem(handle, &(handle->ignoregroup), grp);
}
int SYMEXPORT alpm_option_add_overwrite_file(alpm_handle_t *handle, const char *glob)
{
return _alpm_option_strlist_add(handle, &(handle->overwrite_files), glob);
}
int SYMEXPORT alpm_option_set_overwrite_files(alpm_handle_t *handle, alpm_list_t *globs)
{
return _alpm_option_strlist_set(handle, &(handle->overwrite_files), globs);
}
int SYMEXPORT alpm_option_remove_overwrite_file(alpm_handle_t *handle, const char *glob)
{
return _alpm_option_strlist_rem(handle, &(handle->overwrite_files), glob);
}
int SYMEXPORT alpm_option_add_assumeinstalled(alpm_handle_t *handle, const alpm_depend_t *dep)
{
alpm_depend_t *depcpy;
CHECK_HANDLE(handle, return -1);
ASSERT(dep->mod == ALPM_DEP_MOD_EQ || dep->mod == ALPM_DEP_MOD_ANY,
RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
ASSERT((depcpy = _alpm_dep_dup(dep)), RET_ERR(handle, ALPM_ERR_MEMORY, -1));
/* fill in name_hash in case dep was built by hand */
depcpy->name_hash = _alpm_hash_sdbm(dep->name);
handle->assumeinstalled = alpm_list_add(handle->assumeinstalled, depcpy);
return 0;
}
int SYMEXPORT alpm_option_set_assumeinstalled(alpm_handle_t *handle, alpm_list_t *deps)
{
CHECK_HANDLE(handle, return -1);
if(handle->assumeinstalled) {
alpm_list_free_inner(handle->assumeinstalled, (alpm_list_fn_free)alpm_dep_free);
alpm_list_free(handle->assumeinstalled);
handle->assumeinstalled = NULL;
}
while(deps) {
if(alpm_option_add_assumeinstalled(handle, deps->data) != 0) {
return -1;
}
deps = deps->next;
}
return 0;
}
static int assumeinstalled_cmp(const void *d1, const void *d2)
{
const alpm_depend_t *dep1 = d1;
const alpm_depend_t *dep2 = d2;
if(dep1->name_hash != dep2->name_hash
|| strcmp(dep1->name, dep2->name) != 0) {
return -1;
}
if(dep1->version && dep2->version
&& strcmp(dep1->version, dep2->version) == 0) {
return 0;
}
if(dep1->version == NULL && dep2->version == NULL) {
return 0;
}
return -1;
}
int SYMEXPORT alpm_option_remove_assumeinstalled(alpm_handle_t *handle, const alpm_depend_t *dep)
{
alpm_depend_t *vdata = NULL;
CHECK_HANDLE(handle, return -1);
handle->assumeinstalled = alpm_list_remove(handle->assumeinstalled, dep, &assumeinstalled_cmp, (void **)&vdata);
if(vdata != NULL) {
alpm_dep_free(vdata);
return 1;
}
return 0;
}
int SYMEXPORT alpm_option_add_architecture(alpm_handle_t *handle, const char *arch)
{
handle->architectures = alpm_list_add(handle->architectures, strdup(arch));
return 0;
}
int SYMEXPORT alpm_option_set_architectures(alpm_handle_t *handle, alpm_list_t *arches)
{
CHECK_HANDLE(handle, return -1);
if(handle->architectures) FREELIST(handle->architectures);
handle->architectures = alpm_list_strdup(arches);
return 0;
}
int SYMEXPORT alpm_option_remove_architecture(alpm_handle_t *handle, const char *arch)
{
char *vdata = NULL;
CHECK_HANDLE(handle, return -1);
handle->architectures = alpm_list_remove_str(handle->architectures, arch, &vdata);
if(vdata != NULL) {
FREE(vdata);
return 1;
}
return 0;
}
alpm_db_t SYMEXPORT *alpm_get_localdb(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->db_local;
}
alpm_list_t SYMEXPORT *alpm_get_syncdbs(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return NULL);
return handle->dbs_sync;
}
int SYMEXPORT alpm_option_set_checkspace(alpm_handle_t *handle, int checkspace)
{
CHECK_HANDLE(handle, return -1);
handle->checkspace = checkspace;
return 0;
}
int SYMEXPORT alpm_option_set_dbext(alpm_handle_t *handle, const char *dbext)
{
CHECK_HANDLE(handle, return -1);
ASSERT(dbext, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
if(handle->dbext) {
FREE(handle->dbext);
}
STRDUP(handle->dbext, dbext, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
_alpm_log(handle, ALPM_LOG_DEBUG, "option 'dbext' = %s\n", handle->dbext);
return 0;
}
int SYMEXPORT alpm_option_set_default_siglevel(alpm_handle_t *handle,
int level)
{
CHECK_HANDLE(handle, return -1);
if(level == ALPM_SIG_USE_DEFAULT) {
RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1);
}
#ifdef HAVE_LIBGPGME
handle->siglevel = level;
#else
if(level != 0) {
RET_ERR(handle, ALPM_ERR_MISSING_CAPABILITY_SIGNATURES, -1);
}
#endif
return 0;
}
int SYMEXPORT alpm_option_get_default_siglevel(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return -1);
return handle->siglevel;
}
int SYMEXPORT alpm_option_set_local_file_siglevel(alpm_handle_t *handle,
int level)
{
CHECK_HANDLE(handle, return -1);
#ifdef HAVE_LIBGPGME
handle->localfilesiglevel = level;
#else
if(level != 0 && level != ALPM_SIG_USE_DEFAULT) {
RET_ERR(handle, ALPM_ERR_MISSING_CAPABILITY_SIGNATURES, -1);
}
#endif
return 0;
}
int SYMEXPORT alpm_option_get_local_file_siglevel(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return -1);
if(handle->localfilesiglevel & ALPM_SIG_USE_DEFAULT) {
return handle->siglevel;
} else {
return handle->localfilesiglevel;
}
}
int SYMEXPORT alpm_option_set_remote_file_siglevel(alpm_handle_t *handle,
int level)
{
CHECK_HANDLE(handle, return -1);
#ifdef HAVE_LIBGPGME
handle->remotefilesiglevel = level;
#else
if(level != 0 && level != ALPM_SIG_USE_DEFAULT) {
RET_ERR(handle, ALPM_ERR_MISSING_CAPABILITY_SIGNATURES, -1);
}
#endif
return 0;
}
int SYMEXPORT alpm_option_get_remote_file_siglevel(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return -1);
if(handle->remotefilesiglevel & ALPM_SIG_USE_DEFAULT) {
return handle->siglevel;
} else {
return handle->remotefilesiglevel;
}
}
int SYMEXPORT alpm_option_get_disable_dl_timeout(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return -1);
return handle->disable_dl_timeout;
}
int SYMEXPORT alpm_option_set_disable_dl_timeout(alpm_handle_t *handle,
unsigned short disable_dl_timeout)
{
CHECK_HANDLE(handle, return -1);
handle->disable_dl_timeout = disable_dl_timeout;
return 0;
}
int SYMEXPORT alpm_option_set_parallel_downloads(alpm_handle_t *handle,
unsigned int num_streams)
{
CHECK_HANDLE(handle, return -1);
ASSERT(num_streams >= 1, RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1));
handle->parallel_downloads = num_streams;
return 0;
}
int SYMEXPORT alpm_option_get_disable_sandbox(alpm_handle_t *handle)
{
CHECK_HANDLE(handle, return -1);
return handle->disable_sandbox;
}
int SYMEXPORT alpm_option_set_disable_sandbox(alpm_handle_t *handle,
unsigned short disable_sandbox)
{
CHECK_HANDLE(handle, return -1);
handle->disable_sandbox = disable_sandbox;
return 0;
}

View file

@ -1,134 +0,0 @@
/*
* handle.h
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef ALPM_HANDLE_H
#define ALPM_HANDLE_H
#include <stdio.h>
#include <sys/types.h>
#include <regex.h>
#include "alpm_list.h"
#include "alpm.h"
#include "trans.h"
#ifdef HAVE_LIBCURL
#include <curl/curl.h>
#endif
#define EVENT(h, e) \
do { \
if((h)->eventcb) { \
(h)->eventcb((h)->eventcb_ctx, (alpm_event_t *) (e)); \
} \
} while(0)
#define QUESTION(h, q) \
do { \
if((h)->questioncb) { \
(h)->questioncb((h)->questioncb_ctx, (alpm_question_t *) (q)); \
} \
} while(0)
#define PROGRESS(h, e, p, per, n, r) \
do { \
if((h)->progresscb) { \
(h)->progresscb((h)->progresscb_ctx, e, p, per, n, r); \
} \
} while(0)
struct _alpm_handle_t {
/* internal usage */
alpm_db_t *db_local; /* local db pointer */
alpm_list_t *dbs_sync; /* List of (alpm_db_t *) */
FILE *logstream; /* log file stream pointer */
alpm_trans_t *trans;
#ifdef HAVE_LIBCURL
/* libcurl handle */
CURLM *curlm;
alpm_list_t *server_errors;
#endif
unsigned short disable_dl_timeout;
unsigned short disable_sandbox;
unsigned int parallel_downloads; /* number of download streams */
#ifdef HAVE_LIBGPGME
alpm_list_t *known_keys; /* keys verified to be in our keychain */
#endif
/* callback functions */
alpm_cb_log logcb; /* Log callback function */
void *logcb_ctx;
alpm_cb_download dlcb; /* Download callback function */
void *dlcb_ctx;
alpm_cb_fetch fetchcb; /* Download file callback function */
void *fetchcb_ctx;
alpm_cb_event eventcb;
void *eventcb_ctx;
alpm_cb_question questioncb;
void *questioncb_ctx;
alpm_cb_progress progresscb;
void *progresscb_ctx;
/* filesystem paths */
char *root; /* Root path, default '/' */
char *dbpath; /* Base path to pacman's DBs */
char *logfile; /* Name of the log file */
char *lockfile; /* Name of the lock file */
char *gpgdir; /* Directory where GnuPG files are stored */
char *sandboxuser; /* User to switch to for sensitive operations */
alpm_list_t *cachedirs; /* Paths to pacman cache directories */
alpm_list_t *hookdirs; /* Paths to hook directories */
alpm_list_t *overwrite_files; /* Paths that may be overwritten */
/* package lists */
alpm_list_t *noupgrade; /* List of packages NOT to be upgraded */
alpm_list_t *noextract; /* List of files NOT to extract */
alpm_list_t *ignorepkg; /* List of packages to ignore */
alpm_list_t *ignoregroup; /* List of groups to ignore */
alpm_list_t *assumeinstalled; /* List of virtual packages used to satisfy dependencies */
/* options */
alpm_list_t *architectures; /* Architectures of packages we should allow */
int usesyslog; /* Use syslog instead of logfile? */ /* TODO move to frontend */
int checkspace; /* Check disk space before installing */
char *dbext; /* Sync DB extension */
int siglevel; /* Default signature verification level */
int localfilesiglevel; /* Signature verification level for local file
upgrade operations */
int remotefilesiglevel; /* Signature verification level for remote file
upgrade operations */
/* error code */
alpm_errno_t pm_errno;
/* lock file descriptor */
int lockfd;
};
alpm_handle_t *_alpm_handle_new(void);
void _alpm_handle_free(alpm_handle_t *handle);
int _alpm_handle_lock(alpm_handle_t *handle);
int _alpm_handle_unlock(alpm_handle_t *handle);
alpm_errno_t _alpm_set_directory_option(const char *value,
char **storage, int must_exist);
#endif /* ALPM_HANDLE_H */

View file

@ -1,683 +0,0 @@
/*
* hook.c
*
* Copyright (c) 2015-2025 Pacman Development Team <pacman-dev@lists.archlinux.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, see <http://www.gnu.org/licenses/>.
*/
#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include "handle.h"
#include "hook.h"
#include "ini.h"
#include "log.h"
#include "trans.h"
#include "util.h"
enum _alpm_hook_op_t {
ALPM_HOOK_OP_INSTALL = (1 << 0),
ALPM_HOOK_OP_UPGRADE = (1 << 1),
ALPM_HOOK_OP_REMOVE = (1 << 2),
};
enum _alpm_trigger_type_t {
ALPM_HOOK_TYPE_PACKAGE = 1,
ALPM_HOOK_TYPE_PATH,
};
struct _alpm_trigger_t {
enum _alpm_hook_op_t op;
enum _alpm_trigger_type_t type;
alpm_list_t *targets;
};
struct _alpm_hook_t {
char *name;
char *desc;
alpm_list_t *triggers;
alpm_list_t *depends;
char **cmd;
alpm_list_t *matches;
alpm_hook_when_t when;
int abort_on_fail, needs_targets;
};
struct _alpm_hook_cb_ctx {
alpm_handle_t *handle;
struct _alpm_hook_t *hook;
};
static void _alpm_trigger_free(struct _alpm_trigger_t *trigger)
{
if(trigger) {
FREELIST(trigger->targets);
free(trigger);
}
}
static void _alpm_hook_free(struct _alpm_hook_t *hook)
{
if(hook) {
free(hook->name);
free(hook->desc);
wordsplit_free(hook->cmd);
alpm_list_free_inner(hook->triggers, (alpm_list_fn_free) _alpm_trigger_free);
alpm_list_free(hook->triggers);
alpm_list_free(hook->matches);
FREELIST(hook->depends);
free(hook);
}
}
static int _alpm_trigger_validate(alpm_handle_t *handle,
struct _alpm_trigger_t *trigger, const char *file)
{
int ret = 0;
if(trigger->targets == NULL) {
ret = -1;
_alpm_log(handle, ALPM_LOG_ERROR,
_("Missing trigger targets in hook: %s\n"), file);
}
if(trigger->type == 0) {
ret = -1;
_alpm_log(handle, ALPM_LOG_ERROR,
_("Missing trigger type in hook: %s\n"), file);
}
if(trigger->op == 0) {
ret = -1;
_alpm_log(handle, ALPM_LOG_ERROR,
_("Missing trigger operation in hook: %s\n"), file);
}
return ret;
}
static int _alpm_hook_validate(alpm_handle_t *handle,
struct _alpm_hook_t *hook, const char *file)
{
alpm_list_t *i;
int ret = 0;
if(hook->triggers == NULL) {
/* special case: allow triggerless hooks as a way of creating dummy
* hooks that can be used to mask lower priority hooks */
return 0;
}
for(i = hook->triggers; i; i = i->next) {
if(_alpm_trigger_validate(handle, i->data, file) != 0) {
ret = -1;
}
}
if(hook->cmd == NULL) {
ret = -1;
_alpm_log(handle, ALPM_LOG_ERROR,
_("Missing Exec option in hook: %s\n"), file);
}
if(hook->when == 0) {
ret = -1;
_alpm_log(handle, ALPM_LOG_ERROR,
_("Missing When option in hook: %s\n"), file);
} else if(hook->when != ALPM_HOOK_PRE_TRANSACTION && hook->abort_on_fail) {
_alpm_log(handle, ALPM_LOG_WARNING,
_("AbortOnFail set for PostTransaction hook: %s\n"), file);
}
return ret;
}
static int _alpm_hook_parse_cb(const char *file, int line,
const char *section, char *key, char *value, void *data)
{
struct _alpm_hook_cb_ctx *ctx = data;
alpm_handle_t *handle = ctx->handle;
struct _alpm_hook_t *hook = ctx->hook;
#define error(...) _alpm_log(handle, ALPM_LOG_ERROR, __VA_ARGS__); return 1;
#define warning(...) _alpm_log(handle, ALPM_LOG_WARNING, __VA_ARGS__);
if(!section && !key) {
error(_("error while reading hook %s: %s\n"), file, strerror(errno));
} else if(!section) {
error(_("hook %s line %d: invalid option %s\n"), file, line, key);
} else if(!key) {
/* beginning a new section */
if(strcmp(section, "Trigger") == 0) {
struct _alpm_trigger_t *t;
CALLOC(t, sizeof(struct _alpm_trigger_t), 1, return 1);
hook->triggers = alpm_list_add(hook->triggers, t);
} else if(strcmp(section, "Action") == 0) {
/* no special processing required */
} else {
error(_("hook %s line %d: invalid section %s\n"), file, line, section);
}
} else if(strcmp(section, "Trigger") == 0) {
struct _alpm_trigger_t *t = hook->triggers->prev->data;
if(strcmp(key, "Operation") == 0) {
if(strcmp(value, "Install") == 0) {
t->op |= ALPM_HOOK_OP_INSTALL;
} else if(strcmp(value, "Upgrade") == 0) {
t->op |= ALPM_HOOK_OP_UPGRADE;
} else if(strcmp(value, "Remove") == 0) {
t->op |= ALPM_HOOK_OP_REMOVE;
} else {
error(_("hook %s line %d: invalid value %s\n"), file, line, value);
}
} else if(strcmp(key, "Type") == 0) {
if(t->type != 0) {
warning(_("hook %s line %d: overwriting previous definition of %s\n"), file, line, "Type");
}
if(strcmp(value, "Package") == 0) {
t->type = ALPM_HOOK_TYPE_PACKAGE;
} else if(strcmp(value, "File") == 0) {
_alpm_log(handle, ALPM_LOG_DEBUG,
"File targets are deprecated, use Path instead\n");
t->type = ALPM_HOOK_TYPE_PATH;
} else if(strcmp(value, "Path") == 0) {
t->type = ALPM_HOOK_TYPE_PATH;
} else {
error(_("hook %s line %d: invalid value %s\n"), file, line, value);
}
} else if(strcmp(key, "Target") == 0) {
char *val;
STRDUP(val, value, return 1);
t->targets = alpm_list_add(t->targets, val);
} else {
error(_("hook %s line %d: invalid option %s\n"), file, line, key);
}
} else if(strcmp(section, "Action") == 0) {
if(strcmp(key, "When") == 0) {
if(hook->when != 0) {
warning(_("hook %s line %d: overwriting previous definition of %s\n"), file, line, "When");
}
if(strcmp(value, "PreTransaction") == 0) {
hook->when = ALPM_HOOK_PRE_TRANSACTION;
} else if(strcmp(value, "PostTransaction") == 0) {
hook->when = ALPM_HOOK_POST_TRANSACTION;
} else {
error(_("hook %s line %d: invalid value %s\n"), file, line, value);
}
} else if(strcmp(key, "Description") == 0) {
if(hook->desc != NULL) {
warning(_("hook %s line %d: overwriting previous definition of %s\n"), file, line, "Description");
FREE(hook->desc);
}
STRDUP(hook->desc, value, return 1);
} else if(strcmp(key, "Depends") == 0) {
char *val;
STRDUP(val, value, return 1);
hook->depends = alpm_list_add(hook->depends, val);
} else if(strcmp(key, "AbortOnFail") == 0) {
hook->abort_on_fail = 1;
} else if(strcmp(key, "NeedsTargets") == 0) {
hook->needs_targets = 1;
} else if(strcmp(key, "Exec") == 0) {
if(hook->cmd != NULL) {
warning(_("hook %s line %d: overwriting previous definition of %s\n"), file, line, "Exec");
wordsplit_free(hook->cmd);
}
if((hook->cmd = wordsplit(value)) == NULL) {
if(errno == EINVAL) {
error(_("hook %s line %d: invalid value %s\n"), file, line, value);
} else {
error(_("hook %s line %d: unable to set option (%s)\n"),
file, line, strerror(errno));
}
}
} else {
error(_("hook %s line %d: invalid option %s\n"), file, line, key);
}
}
#undef error
#undef warning
return 0;
}
static int _alpm_hook_trigger_match_file(alpm_handle_t *handle,
struct _alpm_hook_t *hook, struct _alpm_trigger_t *t)
{
alpm_list_t *i, *j, *install = NULL, *upgrade = NULL, *remove = NULL;
size_t isize = 0, rsize = 0;
int ret = 0;
/* check if file will be installed */
for(i = handle->trans->add; i; i = i->next) {
alpm_pkg_t *pkg = i->data;
alpm_filelist_t filelist = pkg->files;
size_t f;
for(f = 0; f < filelist.count; f++) {
if(alpm_option_match_noextract(handle, filelist.files[f].name) == 0) {
continue;
}
if(_alpm_fnmatch_patterns(t->targets, filelist.files[f].name) == 0) {
install = alpm_list_add(install, filelist.files[f].name);
isize++;
}
}
}
/* check if file will be removed due to package upgrade */
for(i = handle->trans->add; i; i = i->next) {
alpm_pkg_t *spkg = i->data;
alpm_pkg_t *pkg = spkg->oldpkg;
if(pkg) {
alpm_filelist_t filelist = pkg->files;
size_t f;
for(f = 0; f < filelist.count; f++) {
if(_alpm_fnmatch_patterns(t->targets, filelist.files[f].name) == 0) {
remove = alpm_list_add(remove, filelist.files[f].name);
rsize++;
}
}
}
}
/* check if file will be removed due to package removal */
for(i = handle->trans->remove; i; i = i->next) {
alpm_pkg_t *pkg = i->data;
alpm_filelist_t filelist = pkg->files;
size_t f;
for(f = 0; f < filelist.count; f++) {
if(_alpm_fnmatch_patterns(t->targets, filelist.files[f].name) == 0) {
remove = alpm_list_add(remove, filelist.files[f].name);
rsize++;
}
}
}
i = install = alpm_list_msort(install, isize, (alpm_list_fn_cmp)strcmp);
j = remove = alpm_list_msort(remove, rsize, (alpm_list_fn_cmp)strcmp);
while(i) {
while(j && strcmp(i->data, j->data) > 0) {
j = j->next;
}
if(j == NULL) {
break;
}
if(strcmp(i->data, j->data) == 0) {
char *path = i->data;
upgrade = alpm_list_add(upgrade, path);
while(i && strcmp(i->data, path) == 0) {
alpm_list_t *next = i->next;
install = alpm_list_remove_item(install, i);
free(i);
i = next;
}
while(j && strcmp(j->data, path) == 0) {
alpm_list_t *next = j->next;
remove = alpm_list_remove_item(remove, j);
free(j);
j = next;
}
} else {
i = i->next;
}
}
ret = (t->op & ALPM_HOOK_OP_INSTALL && install)
|| (t->op & ALPM_HOOK_OP_UPGRADE && upgrade)
|| (t->op & ALPM_HOOK_OP_REMOVE && remove);
if(hook->needs_targets) {
#define _save_matches(_op, _matches) \
if(t->op & _op && _matches) { \
hook->matches = alpm_list_join(hook->matches, _matches); \
} else { \
alpm_list_free(_matches); \
}
_save_matches(ALPM_HOOK_OP_INSTALL, install);
_save_matches(ALPM_HOOK_OP_UPGRADE, upgrade);
_save_matches(ALPM_HOOK_OP_REMOVE, remove);
#undef _save_matches
} else {
alpm_list_free(install);
alpm_list_free(upgrade);
alpm_list_free(remove);
}
return ret;
}
static int _alpm_hook_trigger_match_pkg(alpm_handle_t *handle,
struct _alpm_hook_t *hook, struct _alpm_trigger_t *t)
{
alpm_list_t *install = NULL, *upgrade = NULL, *remove = NULL;
if(t->op & ALPM_HOOK_OP_INSTALL || t->op & ALPM_HOOK_OP_UPGRADE) {
alpm_list_t *i;
for(i = handle->trans->add; i; i = i->next) {
alpm_pkg_t *pkg = i->data;
if(_alpm_fnmatch_patterns(t->targets, pkg->name) == 0) {
if(pkg->oldpkg) {
if(t->op & ALPM_HOOK_OP_UPGRADE) {
if(hook->needs_targets) {
upgrade = alpm_list_add(upgrade, pkg->name);
} else {
return 1;
}
}
} else {
if(t->op & ALPM_HOOK_OP_INSTALL) {
if(hook->needs_targets) {
install = alpm_list_add(install, pkg->name);
} else {
return 1;
}
}
}
}
}
}
if(t->op & ALPM_HOOK_OP_REMOVE) {
alpm_list_t *i;
for(i = handle->trans->remove; i; i = i->next) {
alpm_pkg_t *pkg = i->data;
if(pkg && _alpm_fnmatch_patterns(t->targets, pkg->name) == 0) {
if(!alpm_list_find(handle->trans->add, pkg, _alpm_pkg_cmp)) {
if(hook->needs_targets) {
remove = alpm_list_add(remove, pkg->name);
} else {
return 1;
}
}
}
}
}
/* if we reached this point we either need the target lists or we didn't
* match anything and the following calls will all be no-ops */
hook->matches = alpm_list_join(hook->matches, install);
hook->matches = alpm_list_join(hook->matches, upgrade);
hook->matches = alpm_list_join(hook->matches, remove);
return install || upgrade || remove;
}
static int _alpm_hook_trigger_match(alpm_handle_t *handle,
struct _alpm_hook_t *hook, struct _alpm_trigger_t *t)
{
return t->type == ALPM_HOOK_TYPE_PACKAGE
? _alpm_hook_trigger_match_pkg(handle, hook, t)
: _alpm_hook_trigger_match_file(handle, hook, t);
}
static int _alpm_hook_triggered(alpm_handle_t *handle, struct _alpm_hook_t *hook)
{
alpm_list_t *i;
int ret = 0;
for(i = hook->triggers; i; i = i->next) {
if(_alpm_hook_trigger_match(handle, hook, i->data)) {
if(!hook->needs_targets) {
return 1;
} else {
ret = 1;
}
}
}
return ret;
}
static int _alpm_hook_cmp(struct _alpm_hook_t *h1, struct _alpm_hook_t *h2)
{
size_t suflen = strlen(ALPM_HOOK_SUFFIX), l1, l2;
int ret;
l1 = strlen(h1->name) - suflen;
l2 = strlen(h2->name) - suflen;
/* exclude the suffixes from comparison */
ret = strncmp(h1->name, h2->name, l1 <= l2 ? l1 : l2);
if(ret == 0 && l1 != l2) {
return l1 < l2 ? -1 : 1;
}
return ret;
}
static alpm_list_t *find_hook(alpm_list_t *haystack, const void *needle)
{
while(haystack) {
struct _alpm_hook_t *h = haystack->data;
if(h && strcmp(h->name, needle) == 0) {
return haystack;
}
haystack = haystack->next;
}
return NULL;
}
static ssize_t _alpm_hook_feed_targets(char *buf, ssize_t needed, alpm_list_t **pos)
{
size_t remaining = needed, written = 0;;
size_t len;
while(*pos && (len = strlen((*pos)->data)) + 1 <= remaining) {
memcpy(buf, (*pos)->data, len);
buf[len++] = '\n';
*pos = (*pos)->next;
buf += len;
remaining -= len;
written += len;
}
if(*pos && remaining) {
memcpy(buf, (*pos)->data, remaining);
(*pos)->data = (char*) (*pos)->data + remaining;
written += remaining;
}
return written;
}
static alpm_list_t *_alpm_strlist_dedup(alpm_list_t *list)
{
alpm_list_t *i = list;
while(i) {
alpm_list_t *next = i->next;
while(next && strcmp(i->data, next->data) == 0) {
list = alpm_list_remove_item(list, next);
free(next);
next = i->next;
}
i = next;
}
return list;
}
static int _alpm_hook_run_hook(alpm_handle_t *handle, struct _alpm_hook_t *hook)
{
alpm_list_t *i, *pkgs = _alpm_db_get_pkgcache(handle->db_local);
for(i = hook->depends; i; i = i->next) {
if(!alpm_find_satisfier(pkgs, i->data)) {
_alpm_log(handle, ALPM_LOG_ERROR, _("unable to run hook %s: %s\n"),
hook->name, _("could not satisfy dependencies"));
return -1;
}
}
if(hook->needs_targets) {
alpm_list_t *ctx;
hook->matches = alpm_list_msort(hook->matches,
alpm_list_count(hook->matches), (alpm_list_fn_cmp)strcmp);
/* hooks with multiple triggers could have duplicate matches */
ctx = hook->matches = _alpm_strlist_dedup(hook->matches);
return _alpm_run_chroot(handle, hook->cmd[0], hook->cmd,
(_alpm_cb_io) _alpm_hook_feed_targets, &ctx);
} else {
return _alpm_run_chroot(handle, hook->cmd[0], hook->cmd, NULL, NULL);
}
}
int _alpm_hook_run(alpm_handle_t *handle, alpm_hook_when_t when)
{
alpm_event_hook_t event = { .when = when };
alpm_event_hook_run_t hook_event;
alpm_list_t *i, *hooks = NULL, *hooks_triggered = NULL;
size_t suflen = strlen(ALPM_HOOK_SUFFIX), triggered = 0;
int ret = 0;
for(i = alpm_list_last(handle->hookdirs); i; i = alpm_list_previous(i)) {
char path[PATH_MAX];
size_t dirlen;
struct dirent *entry;
DIR *d;
if((dirlen = strlen(i->data)) >= PATH_MAX) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not open directory: %s: %s\n"),
(char *)i->data, strerror(ENAMETOOLONG));
ret = -1;
continue;
}
memcpy(path, i->data, dirlen + 1);
if(!(d = opendir(path))) {
if(errno == ENOENT) {
continue;
} else {
_alpm_log(handle, ALPM_LOG_ERROR,
_("could not open directory: %s: %s\n"), path, strerror(errno));
ret = -1;
continue;
}
}
while((errno = 0, entry = readdir(d))) {
struct _alpm_hook_cb_ctx ctx = { handle, NULL };
struct stat buf;
size_t name_len;
if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
if((name_len = strlen(entry->d_name)) >= PATH_MAX - dirlen) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not open file: %s%s: %s\n"),
path, entry->d_name, strerror(ENAMETOOLONG));
ret = -1;
continue;
}
memcpy(path + dirlen, entry->d_name, name_len + 1);
if(name_len < suflen
|| strcmp(entry->d_name + name_len - suflen, ALPM_HOOK_SUFFIX) != 0) {
_alpm_log(handle, ALPM_LOG_DEBUG, "skipping non-hook file %s\n", path);
continue;
}
if(find_hook(hooks, entry->d_name)) {
_alpm_log(handle, ALPM_LOG_DEBUG, "skipping overridden hook %s\n", path);
continue;
}
if(stat(path, &buf) != 0) {
_alpm_log(handle, ALPM_LOG_ERROR,
_("could not stat file %s: %s\n"), path, strerror(errno));
ret = -1;
continue;
}
if(S_ISDIR(buf.st_mode)) {
_alpm_log(handle, ALPM_LOG_DEBUG, "skipping directory %s\n", path);
continue;
}
CALLOC(ctx.hook, sizeof(struct _alpm_hook_t), 1,
ret = -1; closedir(d); goto cleanup);
_alpm_log(handle, ALPM_LOG_DEBUG, "parsing hook file %s\n", path);
if(parse_ini(path, _alpm_hook_parse_cb, &ctx) != 0
|| _alpm_hook_validate(handle, ctx.hook, path)) {
_alpm_log(handle, ALPM_LOG_DEBUG, "parsing hook file %s failed\n", path);
_alpm_hook_free(ctx.hook);
ret = -1;
continue;
}
STRDUP(ctx.hook->name, entry->d_name, ret = -1; closedir(d); goto cleanup);
hooks = alpm_list_add(hooks, ctx.hook);
}
if(errno != 0) {
_alpm_log(handle, ALPM_LOG_ERROR, _("could not read directory: %s: %s\n"),
(char *) i->data, strerror(errno));
ret = -1;
}
closedir(d);
}
if(ret != 0 && when == ALPM_HOOK_PRE_TRANSACTION) {
goto cleanup;
}
hooks = alpm_list_msort(hooks, alpm_list_count(hooks),
(alpm_list_fn_cmp)_alpm_hook_cmp);
for(i = hooks; i; i = i->next) {
struct _alpm_hook_t *hook = i->data;
if(hook && hook->when == when && _alpm_hook_triggered(handle, hook)) {
hooks_triggered = alpm_list_add(hooks_triggered, hook);
triggered++;
}
}
if(hooks_triggered != NULL) {
event.type = ALPM_EVENT_HOOK_START;
EVENT(handle, (void *)&event);
hook_event.position = 1;
hook_event.total = triggered;
for(i = hooks_triggered; i; i = i->next, hook_event.position++) {
struct _alpm_hook_t *hook = i->data;
alpm_logaction(handle, ALPM_CALLER_PREFIX, "running '%s'...\n", hook->name);
hook_event.type = ALPM_EVENT_HOOK_RUN_START;
hook_event.name = hook->name;
hook_event.desc = hook->desc;
EVENT(handle, &hook_event);
if(_alpm_hook_run_hook(handle, hook) != 0 && hook->abort_on_fail) {
ret = -1;
}
hook_event.type = ALPM_EVENT_HOOK_RUN_DONE;
EVENT(handle, &hook_event);
if(ret != 0 && when == ALPM_HOOK_PRE_TRANSACTION) {
break;
}
}
alpm_list_free(hooks_triggered);
event.type = ALPM_EVENT_HOOK_DONE;
EVENT(handle, (void *)&event);
}
cleanup:
alpm_list_free_inner(hooks, (alpm_list_fn_free) _alpm_hook_free);
alpm_list_free(hooks);
return ret;
}

View file

@ -1,29 +0,0 @@
/*
* hook.h
*
* Copyright (c) 2015-2025 Pacman Development Team <pacman-dev@lists.archlinux.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, see <http://www.gnu.org/licenses/>.
*/
#ifndef ALPM_HOOK_H
#define ALPM_HOOK_H
#include "alpm.h"
#define ALPM_HOOK_SUFFIX ".hook"
int _alpm_hook_run(alpm_handle_t *handle, alpm_hook_when_t when);
#endif /* ALPM_HOOK_H */

View file

@ -1,51 +0,0 @@
#ifndef LIBARCHIVE_COMPAT_H
#define LIBARCHIVE_COMPAT_H
/*
* libarchive-compat.h
*
* Copyright (c) 2013-2025 Pacman Development Team <pacman-dev@lists.archlinux.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, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
static inline int _alpm_archive_read_free(struct archive *archive)
{
return archive_read_free(archive);
}
static inline int64_t _alpm_archive_compressed_ftell(struct archive *archive)
{
return archive_filter_bytes(archive, -1);
}
static inline int _alpm_archive_read_open_file(struct archive *archive,
const char *filename, size_t block_size)
{
return archive_read_open_filename(archive, filename, block_size);
}
static inline int _alpm_archive_filter_code(struct archive *archive)
{
return archive_filter_code(archive, 0);
}
static inline int _alpm_archive_read_support_filter_all(struct archive *archive)
{
return archive_read_support_filter_all(archive);
}
#endif /* LIBARCHIVE_COMPAT_H */

View file

@ -1,112 +0,0 @@
/*
* log.c
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <syslog.h>
#include <time.h>
/* libalpm */
#include "log.h"
#include "handle.h"
#include "util.h"
#include "alpm.h"
static int _alpm_log_leader(FILE *f, const char *prefix)
{
time_t t = time(NULL);
struct tm *tm = localtime(&t);
int length = 32;
char timestamp[length];
/* Use ISO-8601 date format */
strftime(timestamp,length,"%FT%T%z", tm);
return fprintf(f, "[%s] [%s] ", timestamp, prefix);
}
int SYMEXPORT alpm_logaction(alpm_handle_t *handle, const char *prefix,
const char *fmt, ...)
{
int ret = 0;
va_list args;
ASSERT(handle != NULL, return -1);
if(!(prefix && *prefix)) {
prefix = "UNKNOWN";
}
/* check if the logstream is open already, opening it if needed */
if(handle->logstream == NULL && handle->logfile != NULL) {
int fd;
do {
fd = open(handle->logfile, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC,
0644);
} while(fd == -1 && errno == EINTR);
/* if we couldn't open it, we have an issue */
if(fd < 0 || (handle->logstream = fdopen(fd, "a")) == NULL) {
if(errno == EACCES) {
handle->pm_errno = ALPM_ERR_BADPERMS;
} else if(errno == ENOENT) {
handle->pm_errno = ALPM_ERR_NOT_A_DIR;
} else {
handle->pm_errno = ALPM_ERR_SYSTEM;
}
ret = -1;
}
}
va_start(args, fmt);
if(handle->usesyslog) {
/* we can't use a va_list more than once, so we need to copy it
* so we can use the original when calling vfprintf below. */
va_list args_syslog;
va_copy(args_syslog, args);
vsyslog(LOG_WARNING, fmt, args_syslog);
va_end(args_syslog);
}
if(handle->logstream) {
if(_alpm_log_leader(handle->logstream, prefix) < 0
|| vfprintf(handle->logstream, fmt, args) < 0) {
ret = -1;
handle->pm_errno = ALPM_ERR_SYSTEM;
}
fflush(handle->logstream);
}
va_end(args);
return ret;
}
void _alpm_log(alpm_handle_t *handle, alpm_loglevel_t flag, const char *fmt, ...)
{
va_list args;
if(handle == NULL || handle->logcb == NULL) {
return;
}
va_start(args, fmt);
handle->logcb(handle->logcb_ctx, flag, fmt, args);
va_end(args);
}

View file

@ -1,35 +0,0 @@
libalpm_sources = files('''
add.h add.c
alpm.h alpm.c
alpm_list.h alpm_list.c
backup.h backup.c
base64.h base64.c
be_local.c
be_package.c
be_sync.c
conflict.h conflict.c
db.h db.c
deps.h deps.c
diskspace.h diskspace.c
dload.h dload.c
error.c
filelist.h filelist.c
graph.h graph.c
group.h group.c
handle.h handle.c
hook.h hook.c
libarchive-compat.h
log.h log.c
package.h package.c
pkghash.h pkghash.c
rawstr.c
remove.h remove.c
sandbox.h sandbox.c
sandbox_fs.h sandbox_fs.c
sandbox_syscalls.h sandbox_syscalls.c
signing.c signing.h
sync.h sync.c
trans.h trans.c
util.h util.c
version.c
'''.split())

View file

@ -1,902 +0,0 @@
/*
* package.c
*
* Copyright (c) 2006-2025 Pacman Development Team <pacman-dev@lists.archlinux.org>
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
* Copyright (c) 2005, 2006 by Christian Hamar <krics@linuxforum.hu>
* Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.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, see <http://www.gnu.org/licenses/>.
*/
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
/* libalpm */
#include "package.h"
#include "alpm_list.h"
#include "log.h"
#include "util.h"
#include "db.h"
#include "handle.h"
#include "deps.h"
int SYMEXPORT alpm_pkg_free(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return -1);
/* Only free packages loaded in user space */
if(pkg->origin == ALPM_PKG_FROM_FILE) {
_alpm_pkg_free(pkg);
}
return 0;
}
int SYMEXPORT alpm_pkg_checkmd5sum(alpm_pkg_t *pkg)
{
char *fpath;
int retval;
ASSERT(pkg != NULL, return -1);
pkg->handle->pm_errno = ALPM_ERR_OK;
/* We only inspect packages from sync repositories */
ASSERT(pkg->origin == ALPM_PKG_FROM_SYNCDB,
RET_ERR(pkg->handle, ALPM_ERR_WRONG_ARGS, -1));
fpath = _alpm_filecache_find(pkg->handle, pkg->filename);
retval = _alpm_test_checksum(fpath, pkg->md5sum, ALPM_PKG_VALIDATION_MD5SUM);
FREE(fpath);
if(retval == 1) {
pkg->handle->pm_errno = ALPM_ERR_PKG_INVALID;
retval = -1;
}
return retval;
}
/* Default package accessor functions. These will get overridden by any
* backend logic that needs lazy access, such as the local database through
* a lazy-load cache. However, the defaults will work just fine for fully-
* populated package structures. */
static const char *_pkg_get_base(alpm_pkg_t *pkg) { return pkg->base; }
static const char *_pkg_get_desc(alpm_pkg_t *pkg) { return pkg->desc; }
static const char *_pkg_get_url(alpm_pkg_t *pkg) { return pkg->url; }
static alpm_time_t _pkg_get_builddate(alpm_pkg_t *pkg) { return pkg->builddate; }
static alpm_time_t _pkg_get_installdate(alpm_pkg_t *pkg) { return pkg->installdate; }
static const char *_pkg_get_packager(alpm_pkg_t *pkg) { return pkg->packager; }
static const char *_pkg_get_arch(alpm_pkg_t *pkg) { return pkg->arch; }
static off_t _pkg_get_isize(alpm_pkg_t *pkg) { return pkg->isize; }
static alpm_pkgreason_t _pkg_get_reason(alpm_pkg_t *pkg) { return pkg->reason; }
static int _pkg_get_validation(alpm_pkg_t *pkg) { return pkg->validation; }
static int _pkg_has_scriptlet(alpm_pkg_t *pkg) { return pkg->scriptlet; }
static alpm_list_t *_pkg_get_licenses(alpm_pkg_t *pkg) { return pkg->licenses; }
static alpm_list_t *_pkg_get_groups(alpm_pkg_t *pkg) { return pkg->groups; }
static alpm_list_t *_pkg_get_depends(alpm_pkg_t *pkg) { return pkg->depends; }
static alpm_list_t *_pkg_get_optdepends(alpm_pkg_t *pkg) { return pkg->optdepends; }
static alpm_list_t *_pkg_get_checkdepends(alpm_pkg_t *pkg) { return pkg->checkdepends; }
static alpm_list_t *_pkg_get_makedepends(alpm_pkg_t *pkg) { return pkg->makedepends; }
static alpm_list_t *_pkg_get_conflicts(alpm_pkg_t *pkg) { return pkg->conflicts; }
static alpm_list_t *_pkg_get_provides(alpm_pkg_t *pkg) { return pkg->provides; }
static alpm_list_t *_pkg_get_replaces(alpm_pkg_t *pkg) { return pkg->replaces; }
static alpm_filelist_t *_pkg_get_files(alpm_pkg_t *pkg) { return &(pkg->files); }
static alpm_list_t *_pkg_get_backup(alpm_pkg_t *pkg) { return pkg->backup; }
static alpm_list_t *_pkg_get_xdata(alpm_pkg_t *pkg) { return pkg->xdata; }
static void *_pkg_changelog_open(alpm_pkg_t UNUSED *pkg)
{
return NULL;
}
static size_t _pkg_changelog_read(void UNUSED *ptr, size_t UNUSED size,
const alpm_pkg_t UNUSED *pkg, UNUSED void *fp)
{
return 0;
}
static int _pkg_changelog_close(const alpm_pkg_t UNUSED *pkg,
void UNUSED *fp)
{
return EOF;
}
static struct archive *_pkg_mtree_open(alpm_pkg_t UNUSED *pkg)
{
return NULL;
}
static int _pkg_mtree_next(const alpm_pkg_t UNUSED *pkg,
struct archive UNUSED *archive, struct archive_entry UNUSED **entry)
{
return -1;
}
static int _pkg_mtree_close(const alpm_pkg_t UNUSED *pkg,
struct archive UNUSED *archive)
{
return -1;
}
static int _pkg_force_load(alpm_pkg_t UNUSED *pkg) { return 0; }
/** The standard package operations struct. Get fields directly from the
* struct itself with no abstraction layer or any type of lazy loading.
*/
const struct pkg_operations default_pkg_ops = {
.get_base = _pkg_get_base,
.get_desc = _pkg_get_desc,
.get_url = _pkg_get_url,
.get_builddate = _pkg_get_builddate,
.get_installdate = _pkg_get_installdate,
.get_packager = _pkg_get_packager,
.get_arch = _pkg_get_arch,
.get_isize = _pkg_get_isize,
.get_reason = _pkg_get_reason,
.get_validation = _pkg_get_validation,
.has_scriptlet = _pkg_has_scriptlet,
.get_licenses = _pkg_get_licenses,
.get_groups = _pkg_get_groups,
.get_depends = _pkg_get_depends,
.get_optdepends = _pkg_get_optdepends,
.get_checkdepends = _pkg_get_checkdepends,
.get_makedepends = _pkg_get_makedepends,
.get_conflicts = _pkg_get_conflicts,
.get_provides = _pkg_get_provides,
.get_replaces = _pkg_get_replaces,
.get_files = _pkg_get_files,
.get_backup = _pkg_get_backup,
.get_xdata = _pkg_get_xdata,
.changelog_open = _pkg_changelog_open,
.changelog_read = _pkg_changelog_read,
.changelog_close = _pkg_changelog_close,
.mtree_open = _pkg_mtree_open,
.mtree_next = _pkg_mtree_next,
.mtree_close = _pkg_mtree_close,
.force_load = _pkg_force_load,
};
/* Public functions for getting package information. These functions
* delegate the hard work to the function callbacks attached to each
* package, which depend on where the package was loaded from. */
const char SYMEXPORT *alpm_pkg_get_filename(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->filename;
}
const char SYMEXPORT *alpm_pkg_get_base(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_base(pkg);
}
alpm_handle_t SYMEXPORT *alpm_pkg_get_handle(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
return pkg->handle;
}
const char SYMEXPORT *alpm_pkg_get_name(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->name;
}
const char SYMEXPORT *alpm_pkg_get_version(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->version;
}
alpm_pkgfrom_t SYMEXPORT alpm_pkg_get_origin(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return -1);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->origin;
}
const char SYMEXPORT *alpm_pkg_get_desc(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_desc(pkg);
}
const char SYMEXPORT *alpm_pkg_get_url(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_url(pkg);
}
alpm_time_t SYMEXPORT alpm_pkg_get_builddate(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return -1);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_builddate(pkg);
}
alpm_time_t SYMEXPORT alpm_pkg_get_installdate(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return -1);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_installdate(pkg);
}
const char SYMEXPORT *alpm_pkg_get_packager(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_packager(pkg);
}
const char SYMEXPORT *alpm_pkg_get_md5sum(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->md5sum;
}
const char SYMEXPORT *alpm_pkg_get_sha256sum(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->sha256sum;
}
const char SYMEXPORT *alpm_pkg_get_base64_sig(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->base64_sig;
}
int SYMEXPORT alpm_pkg_get_sig(alpm_pkg_t *pkg, unsigned char **sig, size_t *sig_len)
{
ASSERT(pkg != NULL, return -1);
if(pkg->base64_sig) {
int ret = alpm_decode_signature(pkg->base64_sig, sig, sig_len);
if(ret != 0) {
RET_ERR(pkg->handle, ALPM_ERR_SIG_INVALID, -1);
}
return 0;
} else {
char *pkgpath = NULL, *sigpath = NULL;
alpm_errno_t err;
int ret = -1;
pkgpath = _alpm_filecache_find(pkg->handle, pkg->filename);
if(!pkgpath) {
GOTO_ERR(pkg->handle, ALPM_ERR_PKG_NOT_FOUND, cleanup);
}
sigpath = _alpm_sigpath(pkg->handle, pkgpath);
if(!sigpath || _alpm_access(pkg->handle, NULL, sigpath, R_OK)) {
GOTO_ERR(pkg->handle, ALPM_ERR_SIG_MISSING, cleanup);
}
err = _alpm_read_file(sigpath, sig, sig_len);
if(err == ALPM_ERR_OK) {
_alpm_log(pkg->handle, ALPM_LOG_DEBUG, "found detached signature %s with size %ld\n",
sigpath, *sig_len);
} else {
GOTO_ERR(pkg->handle, err, cleanup);
}
ret = 0;
cleanup:
FREE(pkgpath);
FREE(sigpath);
return ret;
}
}
const char SYMEXPORT *alpm_pkg_get_arch(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_arch(pkg);
}
off_t SYMEXPORT alpm_pkg_get_size(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return -1);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->size;
}
off_t SYMEXPORT alpm_pkg_get_isize(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return -1);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_isize(pkg);
}
alpm_pkgreason_t SYMEXPORT alpm_pkg_get_reason(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return -1);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_reason(pkg);
}
int SYMEXPORT alpm_pkg_get_validation(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return -1);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_validation(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_licenses(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_licenses(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_groups(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_groups(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_depends(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_depends(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_optdepends(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_optdepends(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_checkdepends(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_checkdepends(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_makedepends(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_makedepends(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_conflicts(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_conflicts(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_provides(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_provides(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_replaces(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_replaces(pkg);
}
alpm_filelist_t SYMEXPORT *alpm_pkg_get_files(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_files(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_backup(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_backup(pkg);
}
alpm_db_t SYMEXPORT *alpm_pkg_get_db(alpm_pkg_t *pkg)
{
/* Sanity checks */
ASSERT(pkg != NULL, return NULL);
ASSERT(pkg->origin != ALPM_PKG_FROM_FILE, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->origin_data.db;
}
void SYMEXPORT *alpm_pkg_changelog_open(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->changelog_open(pkg);
}
size_t SYMEXPORT alpm_pkg_changelog_read(void *ptr, size_t size,
const alpm_pkg_t *pkg, void *fp)
{
ASSERT(pkg != NULL, return 0);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->changelog_read(ptr, size, pkg, fp);
}
int SYMEXPORT alpm_pkg_changelog_close(const alpm_pkg_t *pkg, void *fp)
{
ASSERT(pkg != NULL, return -1);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->changelog_close(pkg, fp);
}
struct archive SYMEXPORT *alpm_pkg_mtree_open(alpm_pkg_t * pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->mtree_open(pkg);
}
int SYMEXPORT alpm_pkg_mtree_next(const alpm_pkg_t * pkg, struct archive *archive,
struct archive_entry **entry)
{
ASSERT(pkg != NULL, return -1);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->mtree_next(pkg, archive, entry);
}
int SYMEXPORT alpm_pkg_mtree_close(const alpm_pkg_t * pkg, struct archive *archive)
{
ASSERT(pkg != NULL, return -1);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->mtree_close(pkg, archive);
}
int SYMEXPORT alpm_pkg_has_scriptlet(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return -1);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->has_scriptlet(pkg);
}
alpm_list_t SYMEXPORT *alpm_pkg_get_xdata(alpm_pkg_t *pkg)
{
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
return pkg->ops->get_xdata(pkg);
}
static void find_requiredby(alpm_pkg_t *pkg, alpm_db_t *db, alpm_list_t **reqs,
int optional)
{
const alpm_list_t *i;
pkg->handle->pm_errno = ALPM_ERR_OK;
for(i = _alpm_db_get_pkgcache(db); i; i = i->next) {
alpm_pkg_t *cachepkg = i->data;
alpm_list_t *j;
if(optional == 0) {
j = alpm_pkg_get_depends(cachepkg);
} else {
j = alpm_pkg_get_optdepends(cachepkg);
}
for(; j; j = j->next) {
if(_alpm_depcmp(pkg, j->data)) {
const char *cachepkgname = cachepkg->name;
if(alpm_list_find_str(*reqs, cachepkgname) == NULL) {
*reqs = alpm_list_add(*reqs, strdup(cachepkgname));
}
}
}
}
}
static alpm_list_t *compute_requiredby(alpm_pkg_t *pkg, int optional)
{
const alpm_list_t *i;
alpm_list_t *reqs = NULL;
alpm_db_t *db;
ASSERT(pkg != NULL, return NULL);
pkg->handle->pm_errno = ALPM_ERR_OK;
if(pkg->origin == ALPM_PKG_FROM_FILE) {
/* The sane option; search locally for things that require this. */
find_requiredby(pkg, pkg->handle->db_local, &reqs, optional);
} else {
/* We have a DB package. if it is a local package, then we should
* only search the local DB; else search all known sync databases. */
db = pkg->origin_data.db;
if(db->status & DB_STATUS_LOCAL) {
find_requiredby(pkg, db, &reqs, optional);
} else {
for(i = pkg->handle->dbs_sync; i; i = i->next) {
db = i->data;
find_requiredby(pkg, db, &reqs, optional);
}
reqs = alpm_list_msort(reqs, alpm_list_count(reqs), _alpm_str_cmp);
}
}
return reqs;
}
alpm_list_t SYMEXPORT *alpm_pkg_compute_requiredby(alpm_pkg_t *pkg)
{
return compute_requiredby(pkg, 0);
}
alpm_list_t SYMEXPORT *alpm_pkg_compute_optionalfor(alpm_pkg_t *pkg)
{
return compute_requiredby(pkg, 1);
}
alpm_file_t *_alpm_file_copy(alpm_file_t *dest,
const alpm_file_t *src)
{
STRDUP(dest->name, src->name, return NULL);
dest->size = src->size;
dest->mode = src->mode;
return dest;
}
alpm_pkg_t *_alpm_pkg_new(void)
{
alpm_pkg_t *pkg;
CALLOC(pkg, 1, sizeof(alpm_pkg_t), return NULL);
return pkg;
}
static alpm_list_t *list_depdup(alpm_list_t *old)
{
alpm_list_t *i, *new = NULL;
for(i = old; i; i = i->next) {
new = alpm_list_add(new, _alpm_dep_dup(i->data));
}
return new;
}
/**
* Duplicate a package data struct.
* @param pkg the package to duplicate
* @param new_ptr location to store duplicated package pointer
* @return 0 on success, -1 on fatal error, 1 on non-fatal error
*/
int _alpm_pkg_dup(alpm_pkg_t *pkg, alpm_pkg_t **new_ptr)
{
alpm_pkg_t *newpkg;
alpm_list_t *i;
int ret = 0;
if(!pkg || !pkg->handle) {
return -1;
}
if(!new_ptr) {
RET_ERR(pkg->handle, ALPM_ERR_WRONG_ARGS, -1);
}
if(pkg->ops->force_load(pkg)) {
_alpm_log(pkg->handle, ALPM_LOG_WARNING,
_("could not fully load metadata for package %s-%s\n"),
pkg->name, pkg->version);
ret = 1;
pkg->handle->pm_errno = ALPM_ERR_PKG_INVALID;
}
CALLOC(newpkg, 1, sizeof(alpm_pkg_t), goto cleanup);
newpkg->name_hash = pkg->name_hash;
STRDUP(newpkg->filename, pkg->filename, goto cleanup);
STRDUP(newpkg->base, pkg->base, goto cleanup);
STRDUP(newpkg->name, pkg->name, goto cleanup);
STRDUP(newpkg->version, pkg->version, goto cleanup);
STRDUP(newpkg->desc, pkg->desc, goto cleanup);
STRDUP(newpkg->url, pkg->url, goto cleanup);
newpkg->builddate = pkg->builddate;
newpkg->installdate = pkg->installdate;
STRDUP(newpkg->packager, pkg->packager, goto cleanup);
STRDUP(newpkg->md5sum, pkg->md5sum, goto cleanup);
STRDUP(newpkg->sha256sum, pkg->sha256sum, goto cleanup);
STRDUP(newpkg->arch, pkg->arch, goto cleanup);
newpkg->size = pkg->size;
newpkg->isize = pkg->isize;
newpkg->scriptlet = pkg->scriptlet;
newpkg->reason = pkg->reason;
newpkg->validation = pkg->validation;
newpkg->licenses = alpm_list_strdup(pkg->licenses);
newpkg->replaces = list_depdup(pkg->replaces);
newpkg->groups = alpm_list_strdup(pkg->groups);
for(i = pkg->backup; i; i = i->next) {
newpkg->backup = alpm_list_add(newpkg->backup, _alpm_backup_dup(i->data));
}
newpkg->depends = list_depdup(pkg->depends);
newpkg->optdepends = list_depdup(pkg->optdepends);
newpkg->conflicts = list_depdup(pkg->conflicts);
newpkg->provides = list_depdup(pkg->provides);
if(pkg->files.count) {
size_t filenum;
size_t len = sizeof(alpm_file_t) * pkg->files.count;
MALLOC(newpkg->files.files, len, goto cleanup);
for(filenum = 0; filenum < pkg->files.count; filenum++) {
if(!_alpm_file_copy(newpkg->files.files + filenum,
pkg->files.files + filenum)) {
goto cleanup;
}
}
newpkg->files.count = pkg->files.count;
}
/* internal */
newpkg->infolevel = pkg->infolevel;
newpkg->origin = pkg->origin;
if(newpkg->origin == ALPM_PKG_FROM_FILE) {
STRDUP(newpkg->origin_data.file, pkg->origin_data.file, goto cleanup);
} else {
newpkg->origin_data.db = pkg->origin_data.db;
}
newpkg->ops = pkg->ops;
newpkg->handle = pkg->handle;
*new_ptr = newpkg;
return ret;
cleanup:
_alpm_pkg_free(newpkg);
RET_ERR(pkg->handle, ALPM_ERR_MEMORY, -1);
}
static void free_deplist(alpm_list_t *deps)
{
alpm_list_free_inner(deps, (alpm_list_fn_free)alpm_dep_free);
alpm_list_free(deps);
}
alpm_pkg_xdata_t *_alpm_pkg_parse_xdata(const char *string)
{
alpm_pkg_xdata_t *pd;
const char *sep;
if(string == NULL || (sep = strchr(string, '=')) == NULL) {
return NULL;
}
CALLOC(pd, 1, sizeof(alpm_pkg_xdata_t), return NULL);
STRNDUP(pd->name, string, sep - string, FREE(pd); return NULL);
STRDUP(pd->value, sep + 1, FREE(pd->name); FREE(pd); return NULL);
return pd;
}
void _alpm_pkg_xdata_free(alpm_pkg_xdata_t *pd)
{
if(pd) {
free(pd->name);
free(pd->value);
free(pd);
}
}
void _alpm_pkg_free(alpm_pkg_t *pkg)
{
if(pkg == NULL) {
return;
}
FREE(pkg->filename);
FREE(pkg->base);
FREE(pkg->name);
FREE(pkg->version);
FREE(pkg->desc);
FREE(pkg->url);
FREE(pkg->packager);
FREE(pkg->md5sum);
FREE(pkg->sha256sum);
FREE(pkg->base64_sig);
FREE(pkg->arch);
FREELIST(pkg->licenses);
free_deplist(pkg->replaces);
FREELIST(pkg->groups);
if(pkg->files.count) {
size_t i;
for(i = 0; i < pkg->files.count; i++) {
FREE(pkg->files.files[i].name);
}
free(pkg->files.files);
}
alpm_list_free_inner(pkg->backup, (alpm_list_fn_free)_alpm_backup_free);
alpm_list_free(pkg->backup);
alpm_list_free_inner(pkg->xdata, (alpm_list_fn_free)_alpm_pkg_xdata_free);
alpm_list_free(pkg->xdata);
free_deplist(pkg->depends);
free_deplist(pkg->optdepends);
free_deplist(pkg->checkdepends);
free_deplist(pkg->makedepends);
free_deplist(pkg->conflicts);
free_deplist(pkg->provides);
alpm_list_free(pkg->removes);
_alpm_pkg_free(pkg->oldpkg);
if(pkg->origin == ALPM_PKG_FROM_FILE) {
FREE(pkg->origin_data.file);
}
FREE(pkg);
}
/* This function should be used when removing a target from upgrade/sync target list
* Case 1: If pkg is a loaded package file (ALPM_PKG_FROM_FILE), it will be freed.
* Case 2: If pkg is a pkgcache entry (ALPM_PKG_FROM_CACHE), it won't be freed,
* only the transaction specific fields of pkg will be freed.
*/
void _alpm_pkg_free_trans(alpm_pkg_t *pkg)
{
if(pkg == NULL) {
return;
}
if(pkg->origin == ALPM_PKG_FROM_FILE) {
_alpm_pkg_free(pkg);
return;
}
alpm_list_free(pkg->removes);
pkg->removes = NULL;
_alpm_pkg_free(pkg->oldpkg);
pkg->oldpkg = NULL;
}
/* Is spkg an upgrade for localpkg? */
int _alpm_pkg_compare_versions(alpm_pkg_t *spkg, alpm_pkg_t *localpkg)
{
return alpm_pkg_vercmp(spkg->version, localpkg->version);
}
/* Helper function for comparing packages
*/
int _alpm_pkg_cmp(const void *p1, const void *p2)
{
const alpm_pkg_t *pkg1 = p1;
const alpm_pkg_t *pkg2 = p2;
return strcmp(pkg1->name, pkg2->name);
}
/* Test for existence of a package in a alpm_list_t*
* of alpm_pkg_t*
*/
alpm_pkg_t SYMEXPORT *alpm_pkg_find(alpm_list_t *haystack, const char *needle)
{
alpm_list_t *lp;
unsigned long needle_hash;
if(needle == NULL || haystack == NULL) {
return NULL;
}
needle_hash = _alpm_hash_sdbm(needle);
for(lp = haystack; lp; lp = lp->next) {
alpm_pkg_t *info = lp->data;
if(info) {
if(info->name_hash != needle_hash) {
continue;
}
/* finally: we had hash match, verify string match */
if(strcmp(info->name, needle) == 0) {
return info;
}
}
}
return NULL;
}
int SYMEXPORT alpm_pkg_should_ignore(alpm_handle_t *handle, alpm_pkg_t *pkg)
{
alpm_list_t *groups = NULL;
/* first see if the package is ignored */
if(alpm_list_find(handle->ignorepkg, pkg->name, _alpm_fnmatch)) {
return 1;
}
/* next see if the package is in a group that is ignored */
for(groups = alpm_pkg_get_groups(pkg); groups; groups = groups->next) {
char *grp = groups->data;
if(alpm_list_find(handle->ignoregroup, grp, _alpm_fnmatch)) {
return 1;
}
}
return 0;
}
/* check that package metadata meets our requirements */
int _alpm_pkg_check_meta(alpm_pkg_t *pkg)
{
char *c;
int error_found = 0;
#define EPKGMETA(error) do { \
error_found = -1; \
_alpm_log(pkg->handle, ALPM_LOG_ERROR, error, pkg->name, pkg->version); \
} while(0)
/* sanity check */
if(pkg->handle == NULL) {
return -1;
}
/* immediate bail if package doesn't have name or version */
if(pkg->name == NULL || pkg->name[0] == '\0'
|| pkg->version == NULL || pkg->version[0] == '\0') {
_alpm_log(pkg->handle, ALPM_LOG_ERROR,
_("invalid package metadata (name or version missing)"));
return -1;
}
if(pkg->name[0] == '-' || pkg->name[0] == '.') {
EPKGMETA(_("invalid metadata for package %s-%s "
"(package name cannot start with '.' or '-')\n"));
}
if(_alpm_fnmatch(pkg->name, "[![:alnum:]+_.@-]") == 0) {
EPKGMETA(_("invalid metadata for package %s-%s "
"(package name contains invalid characters)\n"));
}
/* multiple '-' in pkgver can cause local db entries for different packages
* to overlap (e.g. foo-1=2-3 and foo=1-2-3 both give foo-1-2-3) */
if((c = strchr(pkg->version, '-')) && (strchr(c + 1, '-'))) {
EPKGMETA(_("invalid metadata for package %s-%s "
"(package version contains invalid characters)\n"));
}
if(strchr(pkg->version, '/')) {
EPKGMETA(_("invalid metadata for package %s-%s "
"(package version contains invalid characters)\n"));
}
/* local db entry is <pkgname>-<pkgver> */
if(strlen(pkg->name) + strlen(pkg->version) + 1 > NAME_MAX) {
EPKGMETA(_("invalid metadata for package %s-%s "
"(package name and version too long)\n"));
}
#undef EPKGMETA
return error_found;
}

Some files were not shown because too many files have changed in this diff Show more