diff --git a/contrib/pkgconf/CODE_OF_CONDUCT.md b/contrib/pkgconf/CODE_OF_CONDUCT.md index 1dc77b3ef9af..91a68394ea11 100644 --- a/contrib/pkgconf/CODE_OF_CONDUCT.md +++ b/contrib/pkgconf/CODE_OF_CONDUCT.md @@ -1,27 +1,93 @@ # pkgconf Code of Conduct -We invite and encourage everybody to express their opinions on relevant -topics. All participants should at all times feel at ease to do so without -fearing any form of attack, reprisal or harassment. We ask everybody to be -respectful and considerate towards each other, especially when attempting -to provide constructive criticism. +## Human participants -To foster tolerance, respect and hospitality in our community, we agree not -to engage in discriminatory, disparaging or offensive speech or actions, -including as to (but not limited to) gender, sexuality, race, nationality, -religion or profession. We are a community of many different nationalities -and backgrounds, and we cherish our strength in diversity. +Human participants in the pkgconf project are expected to follow the current +version of the [Contributor Covenant][covenant], as posted on +contributor-covenant.org. The version posted there at the time of an +incident is the version that applies. + + [covenant]: https://www.contributor-covenant.org/ + + +## Organizations and agents: respect for maintainer autonomy + +Humans and agents acting on behalf of a corporate project must additionally +respect the autonomy of the pkgconf maintainers. + +The pkgconf maintainers decide what is merged, what is released, what is +supported, what is disclosed, and on what schedule. These decisions are not +subject to the priorities, deadlines, embargoes, or escalation paths of any +outside organization, consortium, or foundation, regardless of who its +members are or how critical it believes pkgconf to be. + +Conduct that disrespects this autonomy includes, but is not limited to: + + * Asserting a disclosure deadline, embargo, or remediation timeline for + pkgconf that the maintainers did not agree to. + * Requiring the maintainers to accept confidentiality obligations as a + condition of receiving a vulnerability report. Reports are welcome on + the maintainers' terms; a report offered only under conditions the + maintainers have not accepted is not a contribution, it is leverage. + * Submitting machine-generated patches, reports, or issues at a volume or + cadence that transfers the cost of review onto the maintainers, or + continuing to do so after being asked to stop. + * Escalating a maintainer decision to the maintainers' employer, to a + downstream distributor, to a funder, or to the press in order to obtain + a different outcome. + * Characterizing pkgconf as unmaintained, abandoned, under-maintained, or + in need of external stewardship, other than by the maintainers + themselves. + +Behavior that disrespects this autonomy will result in an organization-wide +ban: the organization the human or agent is acting on behalf of will be +banned from participation in its entirety, not merely the individual human +or agent involved. Where the actor is a consortium, alliance, or foundation +program, the ban extends to the program as a whole. + + +## "Maintainer of last resort" + +pkgconf is actively maintained. Only the pkgconf maintainers are competent +to declare otherwise, and no such declaration has been made. + +pkgconf is distributed under the ISC license, which permits anyone to copy, +modify, and redistribute the software, including as a fork. Nothing in this +document restricts that right, and forks made under a distinct name are a +legitimate exercise of it. + +The license does not, however, convey the pkgconf name, nor the right to +speak for the pkgconf project or its authors. The following is unwelcome, +and carries the same consequence as any other failure to respect maintainer +autonomy: + + * Representing any person or organization as the maintainer, steward, or + "maintainer of last resort" of pkgconf, whether generally or in response + to a ban under this document. + * Distributing a modified pkgconf under the pkgconf name, or under a name + likely to be mistaken for it, in a manner that presents it as the + upstream project. + * Representing patches, releases, or advisories as authored, reviewed, + endorsed, or sanctioned by the pkgconf project or its authors when they + were not. + +If someone does these things anyway, we will say so plainly and publicly, +for as long as it takes to keep the record straight. Fork the code if you +find it necessary; give the fork your own name and speak for it in your own +voice. ## Reporting incidents -Please report any incidents which may be perceived as violations to -`ariadne+conduct@dereferenced.org`. Incidents will be investigated and, -if warranted, acted upon. +Report anything you believe violates this document to +`ariadne+conduct@ariadne.space`. Reports reach the maintainers directly. +We will look into what you tell us, and we will act on it where action is +warranted. +Reports about a human participant are handled under the Contributor +Covenant. Reports about an organization, or about an agent acting on its +behalf, are decided by the maintainers, and the consequence is the one +described above. -## Credits - -This CoC is derived from the [FSFE Code of Conduct][fsfe-coc]. - - [fsfe-coc]: https://fsfe.org/about/codeofconduct.en.html +You do not need to be a contributor to report something, and you will not +be asked to justify why the conduct troubled you. diff --git a/contrib/pkgconf/CONTRIBUTING.md b/contrib/pkgconf/CONTRIBUTING.md index 1cf308c4368f..4a8b9b4c51db 100644 --- a/contrib/pkgconf/CONTRIBUTING.md +++ b/contrib/pkgconf/CONTRIBUTING.md @@ -77,7 +77,7 @@ By submitting a patch, you affirm that: * You can account for how the contribution was produced. Submitting contributions that you do not understand, cannot explain -or cannot clearly attribute may be treated as harrassment per the +or cannot clearly attribute may be treated as harassment per the pkgconf [Code of Conduct][coc]. Contributions produced primarily by autonomous or agentic systems diff --git a/contrib/pkgconf/Makefile.am b/contrib/pkgconf/Makefile.am index 28f84fffe351..8a2fa559e1f6 100644 --- a/contrib/pkgconf/Makefile.am +++ b/contrib/pkgconf/Makefile.am @@ -12,17 +12,29 @@ nodist_pkgconfig_DATA = libpkgconf.pc ACLOCAL_AMFLAGS = -I m4 AM_CFLAGS = -DPERSONALITY_PATH=\"$(personality_dir)\" -DPKG_DEFAULT_PATH=\"$(pkg_default_dir)\" -DSYSTEM_INCLUDEDIR=\"$(system_includedir)\" -DSYSTEM_LIBDIR=\"$(system_libdir)\" -bin_PROGRAMS = pkgconf bomtool spdxtool +bin_PROGRAMS = pkgconf bomtool spdxtool pccritic lib_LTLIBRARIES = libpkgconf.la EXTRA_DIST = pkg.m4 \ meson.build \ meson_options.txt \ + pkgconf.manifest.in \ + pkgconf.rc.in \ pkgconf.wxs.in \ txt2rtf.py \ libpkgconf/meson.build \ libpkgconf/config.h.meson \ libpkgconf/win-dirent.h \ + fuzzer/meson.build \ + fuzzer/alloc-inject.c \ + fuzzer/alloc-inject.h \ + fuzzer/parser-fuzzer.c \ + fuzzer/replay.c \ + fuzzer/solver-fuzzer.c \ + fuzzer/spdxtool-fuzzer.c \ + fuzzer/solver-corpus/chain \ + fuzzer/solver-corpus/constraints \ + fuzzer/solver-corpus/cycle \ t/cli/about.test \ t/cli/atleast-pkgconfig-version-fail.test \ t/cli/atleast-pkgconfig-version-pass.test \ @@ -32,6 +44,11 @@ EXTRA_DIST = pkg.m4 \ t/cli/atleast-version-pass.test \ t/cli/cflags-libs.test \ t/cli/debug.test \ + t/cli/define-prefix-boundary.test \ + t/cli/define-prefix-boundary-sibling.test \ + t/cli/define-prefix-plain.test \ + t/cli/define-prefix-trailing-slash.test \ + t/cli/define-prefix-trailing-slash-cflags.test \ t/cli/define-variable.test \ t/cli/dont-define-prefix.test \ t/cli/dump-personality-loaded.test \ @@ -65,6 +82,9 @@ EXTRA_DIST = pkg.m4 \ t/cli/max-version-inline-constraint.test \ t/cli/max-version-inline-overrides.test \ t/cli/max-version-pass.test \ + t/cli/maximum-traverse-depth-invalid-env.test \ + t/cli/maximum-traverse-depth-invalid.test \ + t/cli/maximum-traverse-depth-unlimited.test \ t/cli/maximum-traverse-depth.test \ t/cli/missing-package.test \ t/cli/missing-package-error.test \ @@ -84,10 +104,13 @@ EXTRA_DIST = pkg.m4 \ t/cli/short-errors.test \ t/cli/silence-errors.test \ t/cli/simulate.test \ + t/cli/single-package-limit.out \ + t/cli/single-package-limit.test \ t/cli/solution.test \ t/cli/unknown-option.test \ t/cli/validate-warning.test \ t/cli/validate.test \ + t/cli/variable-multiple-packages.test \ t/cli/variable.test \ t/cli/verbose.test \ t/cli/version.test \ @@ -145,6 +168,7 @@ EXTRA_DIST = pkg.m4 \ t/basic/uninstalled-not.test \ t/basic/uninstalled.test \ t/basic/variable-env.test \ + t/basic/variable-multiple-packages.test \ t/basic/variable-no-recursion.test \ t/basic/variable.test \ t/basic/version-atleast-1.test \ @@ -176,8 +200,13 @@ EXTRA_DIST = pkg.m4 \ t/parser/dollar-sign-escape.test \ t/parser/dollar-sign-escape-2.test \ t/parser/dos-lineendings.test \ + t/parser/escape-layers-bare-var-libs.test \ + t/parser/escape-layers-cflags.test \ + t/parser/escape-layers-libs.test \ t/parser/escaped-backslashes-in-output.test \ t/parser/fragment-comment.test \ + t/parser/fragment-escaped-space-var-cflags.test \ + t/parser/fragment-escaped-space-var-libs.test \ t/parser/fragment-escaping-1.test \ t/parser/fragment-escaping-2.test \ t/parser/fragment-escaping-3.test \ @@ -200,7 +229,9 @@ EXTRA_DIST = pkg.m4 \ t/parser/multiline-folding-libs.test \ t/parser/no-trailing-newline.test \ t/parser/paren-quoting.test \ + t/parser/self-referential-fragment.test \ t/parser/shell-quoted-output.test \ + t/parser/spaces-in-paths.test \ t/parser/tilde-quoting-1.test \ t/parser/tilde-quoting-2.test \ t/parser/truncated-files-should-fail-to-parse.test \ @@ -218,6 +249,10 @@ EXTRA_DIST = pkg.m4 \ t/solver/circular-reference-2.test \ t/solver/circular-reference-directpc.test \ t/solver/compound-foo-metapackage-3.test \ + t/solver/conflicts-license.test \ + t/solver/conflicts-modversion.test \ + t/solver/conflicts-print-provides.test \ + t/solver/conflicts-print-requires.test \ t/solver/conflicts-solution-error.test \ t/solver/conflicts-solution-ignore.test \ t/solver/conflicts-solution-is-fine-standalone.test \ @@ -321,6 +356,17 @@ EXTRA_DIST = pkg.m4 \ t/spdxtool/version.test \ t/spdxtool/version-operator.test \ t/spdxtool/with-dependency.test \ + t/pccritic/about.test \ + t/pccritic/help.test \ + t/pccritic/min-score-invalid.test \ + t/pccritic/min-score-out-of-range.test \ + t/pccritic/min-score.test \ + t/pccritic/missing-field.test \ + t/pccritic/no-arguments.test \ + t/pccritic/perfect.test \ + t/pccritic/polluted.test \ + t/pccritic/unknown-package.test \ + t/pccritic/version.test \ t/sbom/license-file-bar.test \ t/sbom/license-file-foo.test \ t/sbom/license-isc.test \ @@ -354,7 +400,27 @@ EXTRA_DIST = pkg.m4 \ t/symlink/pcfiledir_symlink_relative_env12.test \ t/sysroot/cflags-rewriting.test \ t/sysroot/explicit-sysroot.test \ + t/sysroot/fdo-sysroot-system-path-filtering.test \ + t/sysroot/fdo-sysroot-variable-not-rewritten.test \ t/sysroot/idirafter-munge-sysroot.test \ + t/sysroot/inject-bare-sysrootdir.test \ + t/sysroot/inject-common-prefix-derived.test \ + t/sysroot/inject-common-prefix-hardcoded.test \ + t/sysroot/inject-common-prefix-literal.test \ + t/sysroot/inject-explicit-cflags.test \ + t/sysroot/inject-explicit-libs.test \ + t/sysroot/inject-hardcoded-cflags.test \ + t/sysroot/inject-hardcoded-libs.test \ + t/sysroot/inject-isystem-attached.test \ + t/sysroot/inject-isystem-explicit.test \ + t/sysroot/inject-isystem-literal.test \ + t/sysroot/inject-isystem-separate.test \ + t/sysroot/inject-literal-prefixed.test \ + t/sysroot/inject-mixed-fragments.test \ + t/sysroot/inject-multi-fragment-var.test \ + t/sysroot/inject-prefix-derived.test \ + t/sysroot/inject-root-sysroot-hardcoded.test \ + t/sysroot/inject-root-sysroot-isystem.test \ t/sysroot/isystem-munge-sysroot.test \ t/sysroot/isystem-sysroot-prefixed.test \ t/sysroot/no-pc_sysrootdir-rewriting-2.test \ @@ -373,6 +439,10 @@ EXTRA_DIST = pkg.m4 \ t/sysroot/uninstalled-rewriting.test \ t/sysroot/variable-rewriting-1.test \ t/sysroot/variable-rewriting-2.test \ + t/sysroot/windows-drive-path-no-inject.test \ + t/sysroot/windows-sysroot-inject.test \ + t/sysroot/windows-system-libdir-filter.test \ + t/sysroot/windows-top-builddir.test \ t/tuple/billion-laughs.test \ t/tuple/case-sensitivity-1.test \ t/tuple/case-sensitivity-2.test \ @@ -380,6 +450,12 @@ EXTRA_DIST = pkg.m4 \ t/tuple/define-variable.test \ t/tuple/duplicate-upsert.test \ t/tuple/empty-tuple.test \ + t/tuple/escaped-backslash-variable.test \ + t/tuple/escaped-whitespace-variable-dquoted.test \ + t/tuple/escaped-whitespace-variable-nested.test \ + t/tuple/escaped-whitespace-variable-squoted.test \ + t/tuple/escaped-whitespace-variable-unquoted.test \ + t/tuple/escaped-whitespace-variable.test \ t/link-abi/default-c.test \ t/link-abi/cxx-leaf.test \ t/link-abi/cxx-leaf-static.test \ @@ -389,7 +465,15 @@ EXTRA_DIST = pkg.m4 \ t/link-abi/multi-dedup.test \ tests/win-shim.h \ tests/api/test-api.h \ + tests/api/oom.h \ + tests/api/test-oom-spdxtool.c \ tests/lib-relocatable/lib/pkgconfig/foo.pc \ + tests/lib-relocatable/abs-boundary/lib/pkgconfig/boundary.pc \ + tests/lib-relocatable/plain-prefix/lib/pkgconfig/plain.pc \ + tests/lib-relocatable/trailing-prefix/lib/pkgconfig/trailing.pc \ + tests/lib1/self-referential-fragment.pc \ + tests/lib1/maxpkg-first.pc \ + tests/lib1/maxpkg-second.pc \ tests/lib1/argv-parse-2.pc \ tests/lib1/billion-laughs.pc \ tests/lib1/dollar-sign-escape.pc \ @@ -511,6 +595,28 @@ EXTRA_DIST = pkg.m4 \ tests/lib1/duplicate-tuple.pc \ tests/lib1/flag-whitespace.pc \ tests/lib1/flag-whitespace-2.pc \ + tests/lib1/fragment-escaped-space-var.pc \ + tests/lib1/windows-sysroot-inject.pc \ + tests/lib1/windows-sysroot-libdir.pc \ + tests/lib1/windows-system-libdir.pc \ + tests/lib1/windows-top-builddir.pc \ + tests/lib1/spaces-in-paths.pc \ + tests/lib1/sysroot-inject-bare.pc \ + tests/lib1/sysroot-inject-explicit.pc \ + tests/lib1/sysroot-inject-hardcoded.pc \ + tests/lib1/sysroot-inject-isystem-explicit.pc \ + tests/lib1/sysroot-inject-isystem-literal.pc \ + tests/lib1/sysroot-inject-isystem-separate.pc \ + tests/lib1/sysroot-inject-literal.pc \ + tests/lib1/sysroot-inject-mixed.pc \ + tests/lib1/sysroot-inject-multi-fragment.pc \ + tests/lib1/sysroot-inject-prefix.pc \ + tests/lib1/escape-layers-bare-var.pc \ + tests/lib1/escape-layers.pc \ + tests/lib1/sysroot-inject-isystem-attached.pc \ + tests/lib-pccritic/perfect.pc \ + tests/lib-pccritic/polluted.pc \ + tests/lib-pccritic/nodesc.pc \ tests/lib-sbom/meta_package.pc \ tests/lib-sbom/test1.pc \ tests/lib-sbom/test2.pc \ @@ -598,7 +704,8 @@ dist_man_MANS = \ man/pkg.m4.7 \ man/pc.5 \ man/pkgconf-personality.5 \ - man/spdxtool.1 + man/spdxtool.1 \ + man/pccritic.1 pkgconf_LDADD = libpkgconf.la pkgconf_SOURCES = \ @@ -617,7 +724,8 @@ noinst_HEADERS = \ cli/spdxtool/serialize.h \ cli/spdxtool/simplelicensing.h \ cli/spdxtool/software.h \ - cli/spdxtool/util.h + cli/spdxtool/util.h \ + cli/pccritic/critic.h bomtool_LDADD = libpkgconf.la bomtool_SOURCES = \ @@ -637,6 +745,13 @@ spdxtool_SOURCES = \ cli/getopt_long.c spdxtool_CPPFLAGS = -I$(top_srcdir)/libpkgconf -I$(top_srcdir)/cli -I$(top_srcdir)/cli/spdxtool +pccritic_LDADD = libpkgconf.la +pccritic_SOURCES = \ + cli/pccritic/main.c \ + cli/pccritic/critic.c \ + cli/getopt_long.c +pccritic_CPPFLAGS = -I$(top_srcdir)/libpkgconf -I$(top_srcdir)/cli -I$(top_srcdir)/cli/pccritic + API_TEST_PROGS = \ test-api-audit \ test-api-buffer \ @@ -651,6 +766,7 @@ API_TEST_PROGS = \ test-api-queue \ test-api-serialize \ test-api-tuple \ + test-api-util \ test-api-variable \ test-api-version @@ -725,6 +841,16 @@ test_api_tuple_LDADD = $(api_test_ldadd) test_api_tuple_SOURCES = tests/api/test-tuple.c test_api_tuple_CPPFLAGS = $(api_test_cppflags) +test_api_util_LDADD = $(api_test_ldadd) +test_api_util_SOURCES = \ + tests/api/test-util.c \ + cli/spdxtool/core.c \ + cli/spdxtool/software.c \ + cli/spdxtool/serialize.c \ + cli/spdxtool/simplelicensing.c \ + cli/spdxtool/util.c +test_api_util_CPPFLAGS = $(api_test_cppflags) -I$(top_srcdir)/cli/spdxtool + test_api_variable_LDADD = $(api_test_ldadd) test_api_variable_SOURCES = tests/api/test-variable.c test_api_variable_CPPFLAGS = $(api_test_cppflags) @@ -754,6 +880,7 @@ check: pkgconf test-runner $(API_TEST_PROGS) $(builddir)/test-api-queue$(EXEEXT) $(builddir)/test-api-serialize$(EXEEXT) $(builddir)/test-api-tuple$(EXEEXT) + $(builddir)/test-api-util$(EXEEXT) $(builddir)/test-api-variable$(EXEEXT) $(builddir)/test-api-version$(EXEEXT) $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/basic @@ -766,6 +893,7 @@ check: pkgconf test-runner $(API_TEST_PROGS) $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/sbom $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/bomtool $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/spdxtool + $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/pccritic $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/symlink $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/sysroot $(builddir)/test-runner$(EXEEXT) --test-fixtures=$(top_srcdir)/tests --tool-dir="$(PWD)" $(top_srcdir)/t/tuple diff --git a/contrib/pkgconf/Makefile.lite b/contrib/pkgconf/Makefile.lite index 90319026f549..7bdefe119da4 100644 --- a/contrib/pkgconf/Makefile.lite +++ b/contrib/pkgconf/Makefile.lite @@ -60,7 +60,7 @@ all: pkgconf-lite libpkgconf/config.h: @echo '#define PACKAGE_NAME "pkgconf-lite"' >> $@ @echo '#define PACKAGE_BUGREPORT "https://git.dereferenced.org/pkgconf/pkgconf/issues"' >> $@ - @echo '#define PACKAGE_VERSION "2.9.93"' >> $@ + @echo '#define PACKAGE_VERSION "3.0.9"' >> $@ @echo '#define PACKAGE PACKAGE_NAME " " PACKAGE_VERSION' >> $@ pkgconf-lite: preflight libpkgconf/config.h ${PKGCONF_OBJS} diff --git a/contrib/pkgconf/NEWS b/contrib/pkgconf/NEWS index ad31e3529c30..cdfcdbbea3b4 100644 --- a/contrib/pkgconf/NEWS +++ b/contrib/pkgconf/NEWS @@ -1,6 +1,186 @@ Changes from previous version of pkgconf ======================================== +Changes from 3.0.8 to 3.0.9: +---------------------------- + +* Build fixes: + - The Autotools build now includes and runs the spdxtool utility API tests, + ensuring that they are included in release tarballs. + Patch by commitmaniac. + +Changes from 3.0.7 to 3.0.8: +---------------------------- + +* Correctness and portability fixes: + - spdxtool now percent-encodes problematic ASCII characters in generated + SPDX URLs and URNs. Patch by Tuukka Pasanen, sponsored by The FreeBSD + Foundation. + - The built-in pc_path, pc_system_libdirs and pc_system_includedirs variables + now use the platform path separator, fixing their output for multiple paths + on Windows. Patch by Christoph Reiter. + +* Documentation and build fixes: + - Correct the pkgconf(1) description of --variable to document that it prints + values for every module specified on the command line. Patch by Christoph + Reiter. + - Update the bug-report URL embedded by Meson builds to point to the pkgconf + issue tracker on GitHub. + +Changes from 3.0.6 to 3.0.7: +---------------------------- + +* Correctness fixes: + - spdxtool now serializes the SPDX 3.0 suppliedBy property as a single Agent + reference instead of a one-element array, as required by the official JSON + schema. + - bomtool no longer emits PackageDownloadLocation twice for each package. + These fixes were contributed by R. Christian McDonald. + +* Build, packaging and portability fixes: + - The Windows installer uses a default installation directory without a + space in its name. Patch by Kai Pastor. + - Skip the spdxtool allocation-failure test for static builds, where linker + wrapping also intercepts libpkgconf allocations and invalidates the test. + See https://github.com/pkgconf/pkgconf/issues/593. + - Use PKGCONF_ITEM_SIZE instead of PATH_MAX in the test runner, allowing it + to build on systems where PATH_MAX is not declared, such as GNU Hurd. + See https://github.com/pkgconf/pkgconf/issues/600. + +Changes from 3.0.5 to 3.0.6: +---------------------------- + +* Command-line behavior: + - --variable accepts multiple modules and prints the requested + variable's value for each module, in argument order. --path and + --print-variables remain limited to a single module. + - pccritic no longer reports the PC061 style finding for CRLF line endings, + avoiding a noisy warning for normal Windows files. + See https://github.com/pkgconf/pkgconf/issues/587. + +* Build and portability fixes: + - Improve OS/2 support by exporting libpkgconf APIs from DLL builds, + recognizing OS/2 drive letters and path separators, comparing paths without + case sensitivity, and using binary mode for redirected standard output and + error. Patches by KO Myung-Hun. + - Declare pkgconf long-path-aware in its Windows application manifest, + allowing paths beyond the traditional MAX_PATH limit when long paths are + enabled by the operating system. Patch by moi15moi. + +Changes from 3.0.4 to 3.0.5: +---------------------------- + +* Correctness fixes: + - Shell quoting and backslash escapes in pc(5) properties are now consumed + once, after variable substitution, instead of while splitting the property + beforehand. Quoting arriving from a variable is therefore treated like + quoting written inline, --variable reports a value as the .pc file spells + it, and fragments are escaped exactly once when rendered. This supersedes + the 3.0.4 fix, which unescaped whitespace at parse time and so hid the + escaping from consumers such as cmake's FindPkgConfig. + See https://github.com/pkgconf/pkgconf/issues/575 and + https://github.com/pkgconf/pkgconf/issues/579. + - Metadata queries no longer consult Conflicts rules between the modules named + on the command line, as reporting metadata does not combine them into a + build. This covers --license, --license-file, --modversion, --path, + --print-provides, --print-requires, --print-requires-private, + --print-variables, --source and --variable. --cflags, --libs and --exists + are unaffected. + See https://github.com/pkgconf/pkgconf/issues/580. + - ${pc_sysrootdir} is now injected into the path taken by every -isystem and + -idirafter flag in a fragment list, rather than only the first. + - -isystem and -idirafter written joined to their path, as in `-isystem/opt`, + are split into the flag and the path it takes, so that the path is subject + to the same sysroot injection and deduplication as the separated spelling. + - Sysroot injection is decided by reading the fragment's path instead of + remembering whether ${pc_sysrootdir} was expanded, so a path which already + lies under the sysroot never acquires a doubled prefix. + +* Performance: + - The package cache and the fragment deduplication index are kept sorted and + searched with bsearch() rather than re-sorted or scanned linearly. + - Variable keys and fragment text are stored with the structures they belong + to, and buffers are rewound and reused rather than reallocated. + - Escaping, fragment rendering and path relocation write into their + destination buffer directly. + Resolving a graph of roughly forty modules is about six times faster than + 3.0.4, and a small graph such as gio-2.0 about twice as fast. + +* Build and portability fixes: + - Fix the pkgconf-lite build, which failed to link because the dependency list + renderer had come to depend on tracing machinery that pkgconf-lite omits. + - Fix the test runner failing to build on MinGW, where the mkdtemp(3) fallback + was compiled only for MSVC builds. + See https://github.com/pkgconf/pkgconf/issues/582. + - The meson build now defines HAVE_DECL_READLINKAT, so readlinkat(2) is used + where it is available instead of always falling back to readlink(2). + The MinGW and readlinkat fixes are by moi15moi. + +* New libpkgconf API additions: + - pkgconf_argv_split_raw: splits a string into an argument vector like + pkgconf_argv_split, but leaves the quoting it reads in place. + - pkgconf_fragment_filter_splice: like pkgconf_fragment_filter, but moves the + matching fragments to the destination list instead of copying them. + - pkgconf_charset_from_spans: compiles a span list into a byte set. + - pkgconf_buffer_escape_charset: escapes a buffer against such a byte set. + - pkgconf_buffer_rewind: empties a buffer while keeping its allocation. + - pkgconf_list_splice: moves the contents of one list onto the end of another. + +Changes from 3.0.3 to 3.0.4: +---------------------------- + +* Fix a crash (stack overflow) triggered by a crafted .pc file containing a + self-referential fragment variable, such as `x=$${x}` referenced from Cflags. + Fragment variables are now evaluated only once while re-splitting. Found + through fuzzing. + +* Fix over-escaping of variable values containing backslash-escaped whitespace, + such as paths quoted with `printf %q`. Such a value was stored with its + escapes intact and then escaped a second time when rendered into a fragment, + producing output like `-L/a\\\ dir`. This broke meson's test suite, which + uses paths with spaces to stay Windows-safe. + +* Fix mangled and duplicated -L/-I paths on Windows when PKG_CONFIG_SYSROOT_DIR + and PKG_CONFIG_LIBDIR are set. Path separators are now normalized to forward + slashes for all runtime-injected paths (sysroot, build root, search paths and + pcfiledir), so that sysroot matching and injection operate on a consistent + basis. + +* Fix `--define-prefix` dropping a path separator when the redefined prefix ends + with a trailing slash, and only rewrite a package's directories when they match + the original prefix on a path component boundary. + +* Fix single-package queries returning results drawn from more than the requested + module, by restoring the package limit that was lost during a refactor of the + query builder. + +Changes from 3.0.2 to 3.0.3: +---------------------------- + +* Restore correct handling of sysroots when emulating legacy pkg-config, and + add explicit regression tests for this case. + +* Fix references to bomtool in spdxtool --help. + Patch by Pierre Pronchery. + +* Fix various typos in the source code. + Patch by Christian Clauss. + +Changes from 3.0.1 to 3.0.2: +---------------------------- + +* Fix build on systems where readlinkat(2) is missing, such as Illumos when + built without appropriate CFLAGS. + +* Fix detection of readlinkat(2) on systems where it is gated behind + _ATFILE_SOURCE, such as on certain builds of Illumos. + +Changes from 3.0.0 to 3.0.1: +---------------------------- + +* Various Meson-related fixes and improvements. + Patches by Benjamin Gilbert. + Changes from 2.5.1 to 3.0.0: ---------------------------- @@ -38,13 +218,21 @@ Changes from 2.5.1 to 3.0.0: PackageDownloadLocation is derived from the Source tag, and SPDX 2.3 package names are used. Patches by Stéphane Rochoy and Tuukka Pasanen. +* New pccritic(1) utility which scores the quality of pc(5) files. Each module + or .pc file is graded from A to F based on findings across several categories: + required and recommended metadata, version sanity, relocatability of libdir + and includedir, Cflags and Libs hygiene, the Requires relationship, the NTIA + SBOM minimum elements, and file-formatting style. Supports --quiet for a + one-line score per target, --min-score for use as a CI gate, and colorized + output. + * New test and I/O framework. - kyua is no longer required to run tests. - Declarative configuration for integration tests, C unit tests for functional tests. - Tests now run on Windows. - .pc and personality files are now opened in binary mode, and the line reader - was reworked to correctly handle CRLF line endings and to avoid getc/ungetc - for better performance. Binary-mode handling by moi15moi. + was reworked to correctly handle LF, CRLF and lone-CR line endings, including + on non-seekable streams. Binary-mode handling by moi15moi. Major contributions by Elizabeth Ashford. * New pc(5) features: @@ -89,8 +277,17 @@ Changes from 2.5.1 to 3.0.0: - Variable substitution is now guarded against denial-of-service inputs, including billion-laughs style expansion and excessively complex bytecode programs. + - Dependency traversal is now limited to 256 levels by default to prevent + stack exhaustion from excessively deep graphs. A depth of -1 explicitly + enables unlimited traversal. + - Bytecode validation now uses overflow-safe bounds checks and rejects + truncated, oversized and otherwise malformed programs. + - Dynamic buffers now reject overlapping source and destination storage and + guard allocation-size arithmetic against overflow. - LLVM libFuzzer targets were added for the pc(5) parser and the solver, and the numerous out-of-memory and crash paths they surfaced were hardened. + - Allocation failures are now propagated through parsing, rendering, output + and SBOM generation instead of silently producing partial results. - Dropped use of strlcpy, strlcat and other silently truncating string functions. @@ -110,6 +307,11 @@ Changes from 2.5.1 to 3.0.0: WantDefaultStatic. - The vestigial --relocate=path option, which existed only for the old test suite, has been removed. + - pccritic --min-score now strictly accepts integer values from 0 through 100. + +* Build system changes: + - The meson build gained a with-pkg-config-dir option to override the default + package search path, matching the autotools --with-pkg-config-dir option. * pkg.m4 changes: - PKG_WITH_MODULES now properly quotes its action arguments (serial 16). @@ -145,8 +347,9 @@ Changes from 2.5.1 to 3.0.0: - SPDX license expressions in the License field are now properly parsed and validated. Patches by Tuukka Pasanen. -* The libpkgconf API and ABI were substantially reworked, breaking ABI - compatibility. The libpkgconf soversion is now 8. +* The libpkgconf API and ABI were substantially reworked, breaking both API and + ABI compatibility. Consumers will need source changes as well as a rebuild. + The libpkgconf soversion is now 8. - An abstract pkgconf_buffer_t type is now used throughout libpkgconf in place of fixed-size stack buffers, removing a class of truncation bugs. - A new pkgconf_output API abstracts all output, allowing the output stream to @@ -155,9 +358,22 @@ Changes from 2.5.1 to 3.0.0: - The pkgconf_tuple_parse API has been removed; variables are now evaluated via pkgconf_variable_eval (backed by the new bytecode engine). - The fragment rendering API was reworked around pkgconf_buffer_t, and the old - pkgconf_fragment_render API has been removed. + pkgconf_fragment_render API has been removed. Fragment renderer callbacks + and pkgconf_fragment_render_buf now return bool so allocation and rendering + failures can be reported. + - pkgconf_license_render now returns bool so allocation failures can be + reported. - The package copyright field was migrated to a bufferset. - Environment variable lookups can now be mocked via pkgconf_client_getenv. + - Client construction gained an options-based API: pkgconf_client_init_with_options + and pkgconf_client_new_with_options accept a pkgconf_client_options_t struct, with + the original pkgconf_client_init and pkgconf_client_new retained as wrappers. The + unveil handler may now be supplied directly as a client option. + - New pkgconf_variable_eval_name API, which evaluates a named variable and + applies sysroot fixups to the result. + - The pkgconf_pkg_traverse_func_t callback gained a trailing iter_flags + argument carrying per-traversal state (PKGCONF_PKG_ITERF_*), replacing the + removed PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE client flag. Changes from 2.5.0 to 2.5.1: ---------------------------- @@ -374,7 +590,7 @@ Changes from 2.0.0 to 2.0.1: The order of --modversion output is based on the dependency resolution queue which is passed to the solver, which itself generally maps to the - order of the constrants provided on the command line. + order of the constraints provided on the command line. * A new flag, --verbose, has been added. When used with `--modversion`, it is possible to disambiguate which version belongs to which module: diff --git a/contrib/pkgconf/cli/bomtool/main.c b/contrib/pkgconf/cli/bomtool/main.c index 3a6f81aeb0bf..7b63cc7e4bd0 100644 --- a/contrib/pkgconf/cli/bomtool/main.c +++ b/contrib/pkgconf/cli/bomtool/main.c @@ -209,8 +209,10 @@ write_copyright_lines(pkgconf_client_t *client, const pkgconf_list_t *copyright_ } static void -write_sbom_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused) +write_sbom_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused, unsigned int iter_flags) { + (void) iter_flags; + pkgconf_buffer_t license_buf = PKGCONF_BUFFER_INITIALIZER; (void) client; (void) unused; @@ -222,9 +224,8 @@ write_sbom_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused) OUTPUT_OR_RET(client, sbom_out, "PackageName: %s\n", sbom_identity(pkg)); OUTPUT_OR_RET(client, sbom_out, "SPDXID: SPDXRef-Package-%s\n", sbom_spdx_identity(pkg)); OUTPUT_OR_RET(client, sbom_out, "PackageVersion: %s\n", pkg->version); - OUTPUT_OR_RET(client, sbom_out, "PackageDownloadLocation: NOASSERTION\n"); - /* NOASSERTION is not a valide value for PackageVerificationCode. It + /* NOASSERTION is not a valid value for PackageVerificationCode. It * expect 40 lowercase hexadecimal digits. */ #if 0 @@ -240,7 +241,13 @@ write_sbom_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused) if (pkg->license.head != NULL) { - pkgconf_license_render(client, &pkg->license, &license_buf); + if (!pkgconf_license_render(client, &pkg->license, &license_buf)) + { + pkgconf_buffer_finalize(&license_buf); + pkgconf_error(client, "bomtool: could not render package license"); + return; + } + bool ret = pkgconf_output_file_fmt(sbom_out, "PackageLicenseDeclared: %s\n", pkgconf_buffer_str_or_empty(&license_buf)); int errno_save = errno; pkgconf_buffer_finalize(&license_buf); @@ -269,8 +276,10 @@ write_sbom_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused) } static void -write_sbom_relationships(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused) +write_sbom_relationships(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused, unsigned int iter_flags) { + (void) iter_flags; + (void) client; (void) unused; @@ -433,7 +442,12 @@ main(int argc, char *argv[]) } } - pkgconf_client_init(&pkg_client, error_handler, NULL, personality, NULL, environ_lookup_handler); + pkgconf_client_options_t client_options = { + .error_handler = error_handler, + .personality = personality, + .environ_lookup_handler = environ_lookup_handler, + }; + pkgconf_client_init_with_options(&pkg_client, &client_options); /* we have determined what features we want most likely. in some cases, we override later. */ pkgconf_client_set_flags(&pkg_client, want_client_flags); @@ -458,10 +472,15 @@ main(int argc, char *argv[]) while (pkg_optind < argc && argv[pkg_optind] != NULL) { - if (pkgconf_buffer_len(&queryparams) > 0) - pkgconf_buffer_push_byte(&queryparams, ' '); + if ((pkgconf_buffer_len(&queryparams) > 0 && + !pkgconf_buffer_push_byte(&queryparams, ' ')) || + !pkgconf_buffer_append(&queryparams, argv[pkg_optind])) + { + pkgconf_buffer_finalize(&queryparams); + ret = EXIT_FAILURE; + goto out; + } - pkgconf_buffer_append(&queryparams, argv[pkg_optind]); pkg_optind++; } diff --git a/contrib/pkgconf/cli/core.c b/contrib/pkgconf/cli/core.c index dfc849ac5ec9..9311f3c9ff04 100644 --- a/contrib/pkgconf/cli/core.c +++ b/contrib/pkgconf/cli/core.c @@ -170,8 +170,10 @@ apply_provides(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int #ifndef PKGCONF_LITE static void -print_digraph_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) +print_digraph_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags) { + (void) iter_flags; + pkgconf_node_t *node; pkgconf_pkg_t **last_seen = data; @@ -272,8 +274,10 @@ apply_digraph(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int ma } static void -print_solution_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused) +print_solution_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *unused, unsigned int iter_flags) { + (void) iter_flags; + (void) unused; pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s (%llu)%s\n", @@ -372,32 +376,6 @@ apply_path(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unused, int max return true; } -static char * -variable_eval(pkgconf_client_t *client, const pkgconf_list_t *vars, const char *varname) -{ - pkgconf_buffer_t varbuf = PKGCONF_BUFFER_INITIALIZER; - const pkgconf_buffer_t *sysroot_dir = PKGCONF_BUFFER_FROM_STR(client->sysroot_dir); - bool saw_sysroot = false; - pkgconf_variable_t *v; - - pkgconf_bytecode_eval_ctx_t ctx = { - .client = client, - .vars = vars, - }; - - v = pkgconf_bytecode_eval_lookup_var(&ctx, varname, strlen(varname)); - (void) pkgconf_variable_eval(client, vars, v, &varbuf, &saw_sysroot); - - if (!saw_sysroot && pkgconf_path_is_plausible(&varbuf)) - { - /* if sysroot is set, and value does not already begin with sysroot */ - if (!pkgconf_buffer_has_prefix(&varbuf, sysroot_dir)) - pkgconf_buffer_prepend(&varbuf, pkgconf_buffer_str_or_empty(sysroot_dir)); - } - - return pkgconf_buffer_freeze(&varbuf); -} - static bool apply_variable(pkgconf_client_t *client, pkgconf_pkg_t *world, const void *variable, int maxdepth) { @@ -413,7 +391,7 @@ apply_variable(pkgconf_client_t *client, pkgconf_pkg_t *world, const void *varia if (pkg == NULL) continue; - result = variable_eval(client, &pkg->vars, variable); + result = pkgconf_variable_eval_name(client, &pkg->vars, variable); if (result != NULL) { @@ -439,12 +417,13 @@ apply_env_var(const char *prefix, pkgconf_client_t *client, pkgconf_pkg_t *world pkgconf_list_t filtered_list = PKGCONF_LIST_INITIALIZER; pkgconf_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER; unsigned int eflag; + bool ret = true; eflag = collect_fn(client, world, &unfiltered_list, maxdepth); if (eflag != PKGCONF_PKG_ERRF_OK) return false; - pkgconf_fragment_filter(client, &filtered_list, &unfiltered_list, filter_fn, NULL); + pkgconf_fragment_filter_splice(client, &filtered_list, &unfiltered_list, filter_fn, NULL); if (postprocess_fn != NULL) postprocess_fn(client, world, &filtered_list); @@ -452,16 +431,22 @@ apply_env_var(const char *prefix, pkgconf_client_t *client, pkgconf_pkg_t *world if (filtered_list.head == NULL) goto out; - pkgconf_fragment_render_buf(&filtered_list, &render_buf, true, state->want_render_ops, (state->want_flags & PKG_NEWLINES) ? '\n' : ' '); - pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s='%s'\n", + if (!pkgconf_fragment_render_buf(&filtered_list, &render_buf, true, state->want_render_ops, + (state->want_flags & PKG_NEWLINES) ? '\n' : ' ')) + { + ret = false; + goto out; + } + + ret = pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s='%s'\n", prefix, pkgconf_buffer_str_or_empty(&render_buf)); - pkgconf_buffer_finalize(&render_buf); out: + pkgconf_buffer_finalize(&render_buf); pkgconf_fragment_free(&unfiltered_list); pkgconf_fragment_free(&filtered_list); - return true; + return ret; } static void @@ -595,13 +580,13 @@ apply_cflags(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *tar if (eflag != PKGCONF_PKG_ERRF_OK) return false; - pkgconf_fragment_filter(client, &filtered_list, &unfiltered_list, filter_cflags, NULL); + pkgconf_fragment_filter_splice(client, &filtered_list, &unfiltered_list, filter_cflags, NULL); maybe_add_module_definitions(client, world, &filtered_list); if (filtered_list.head == NULL) goto out; - pkgconf_fragment_copy_list(client, target_list, &filtered_list); + pkgconf_list_splice(target_list, &filtered_list); out: pkgconf_fragment_free(&unfiltered_list); @@ -621,12 +606,12 @@ apply_libs(pkgconf_client_t *client, pkgconf_pkg_t *world, pkgconf_list_t *targe if (eflag != PKGCONF_PKG_ERRF_OK) return false; - pkgconf_fragment_filter(client, &filtered_list, &unfiltered_list, filter_libs, NULL); + pkgconf_fragment_filter_splice(client, &filtered_list, &unfiltered_list, filter_libs, NULL); if (filtered_list.head == NULL) goto out; - pkgconf_fragment_copy_list(client, target_list, &filtered_list); + pkgconf_list_splice(target_list, &filtered_list); out: pkgconf_fragment_free(&unfiltered_list); @@ -671,8 +656,10 @@ apply_requires_private(pkgconf_client_t *client, pkgconf_pkg_t *world, void *unu } static void -check_uninstalled(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) +check_uninstalled(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags) { + (void) iter_flags; + int *retval = data; (void) client; @@ -695,8 +682,10 @@ apply_uninstalled(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, in #ifndef PKGCONF_LITE static void -print_graph_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) +print_graph_node(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags) { + (void) iter_flags; + pkgconf_node_t *n; (void) data; @@ -788,10 +777,12 @@ apply_fragment_tree(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, } static void -print_license(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) +print_license(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags) { + (void) iter_flags; + pkgconf_buffer_t render_buf = PKGCONF_BUFFER_INITIALIZER; - (void) data; + int *retval = data; if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL) return; @@ -804,9 +795,11 @@ print_license(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) else { /* NOASSERTION is the default when the license is unknown, per SPDX spec § 3.15 */ - pkgconf_license_render(client, &pkg->license, &render_buf); - pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s: ", pkg->id); - pkgconf_output_putbuf(client->output, PKGCONF_OUTPUT_STDOUT, &render_buf, true); + if (!pkgconf_license_render(client, &pkg->license, &render_buf) || + !pkgconf_output_fmt(client->output, PKGCONF_OUTPUT_STDOUT, "%s: ", pkg->id) || + !pkgconf_output_putbuf(client->output, PKGCONF_OUTPUT_STDOUT, &render_buf, true)) + *retval = EXIT_FAILURE; + pkgconf_buffer_finalize(&render_buf); } } @@ -843,10 +836,15 @@ apply_link_abi(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int m { pkgconf_bufferset_t *tag = node->data; - if (pkgconf_buffer_len(&render_buf)) - pkgconf_buffer_push_byte(&render_buf, ' '); - - pkgconf_buffer_append(&render_buf, pkgconf_buffer_str(&tag->buffer)); + if ((pkgconf_buffer_len(&render_buf) && + !pkgconf_buffer_push_byte(&render_buf, ' ')) || + !pkgconf_buffer_append(&render_buf, pkgconf_buffer_str(&tag->buffer))) + { + pkgconf_buffer_finalize(&render_buf); + pkgconf_bufferset_free(&abis); + *retval = EXIT_FAILURE; + return false; + } } pkgconf_output_putbuf(client->output, PKGCONF_OUTPUT_STDOUT, &render_buf, true); @@ -858,8 +856,10 @@ apply_link_abi(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int m } static void -print_license_file(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) +print_license_file(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags) { + (void) iter_flags; + (void) data; if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL) @@ -884,8 +884,10 @@ apply_license_file(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, i } static void -print_source(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) +print_source(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags) { + (void) iter_flags; + (void) data; if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL) @@ -909,7 +911,7 @@ apply_source(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int max return true; } -void +bool path_list_to_buffer(const pkgconf_list_t *list, pkgconf_buffer_t *buffer, char delim) { pkgconf_node_t *n; @@ -919,10 +921,16 @@ path_list_to_buffer(const pkgconf_list_t *list, pkgconf_buffer_t *buffer, char d pkgconf_path_t *pn = n->data; if (n != list->head) - pkgconf_buffer_push_byte(buffer, delim); + { + if (!pkgconf_buffer_push_byte(buffer, delim)) + return false; + } - pkgconf_buffer_append(buffer, pn->path); + if (!pkgconf_buffer_append(buffer, pn->path)) + return false; } + + return true; } static void @@ -947,62 +955,56 @@ unveil_search_paths(pkgconf_client_t *client, const pkgconf_cross_personality_t } } -/* SAFETY: pkgconf_client_t takes ownership of these package objects */ +static bool +register_builtin(pkgconf_client_t *client, const char *id, + const pkgconf_buffer_t *pc_path_buf, + const pkgconf_buffer_t *pc_system_libdirs_buf, + const pkgconf_buffer_t *pc_system_includedirs_buf) +{ + pkgconf_pkg_t *pkg = calloc(1, sizeof(pkgconf_pkg_t)); + if (pkg == NULL) + return false; + + pkg->owner = client; + pkg->id = strdup(id); + pkg->realname = strdup(id); + pkg->description = strdup("virtual package defining pkgconf API version supported"); + pkg->url = strdup(PACKAGE_BUGREPORT); + pkg->version = strdup(PACKAGE_VERSION); + + if (pkg->id == NULL || + pkg->realname == NULL || + pkg->description == NULL || + pkg->url == NULL || + pkg->version == NULL || + pkgconf_tuple_add(client, &pkg->vars, "pc_system_libdirs", pkgconf_buffer_str_or_empty(pc_system_libdirs_buf), false, 0) == NULL || + pkgconf_tuple_add(client, &pkg->vars, "pc_system_includedirs", pkgconf_buffer_str_or_empty(pc_system_includedirs_buf), false, 0) == NULL || + pkgconf_tuple_add(client, &pkg->vars, "pc_path", pkgconf_buffer_str_or_empty(pc_path_buf), false, 0) == NULL || + !pkgconf_client_preload_one(client, pkg)) + { + pkgconf_pkg_free(client, pkg); + return false; + } + + return true; +} + +/* SAFETY: pkgconf_client_t takes ownership of successfully registered package objects */ static void register_builtins(pkgconf_client_t *client, const pkgconf_cross_personality_t *personality) { pkgconf_buffer_t pc_path_buf = PKGCONF_BUFFER_INITIALIZER; - path_list_to_buffer(&personality->dir_list, &pc_path_buf, ':'); - pkgconf_buffer_t pc_system_libdirs_buf = PKGCONF_BUFFER_INITIALIZER; - path_list_to_buffer(&personality->filter_libdirs, &pc_system_libdirs_buf, ':'); - pkgconf_buffer_t pc_system_includedirs_buf = PKGCONF_BUFFER_INITIALIZER; - path_list_to_buffer(&personality->filter_includedirs, &pc_system_includedirs_buf, ':'); - pkgconf_pkg_t *pkg_config_virtual = calloc(1, sizeof(pkgconf_pkg_t)); - if (pkg_config_virtual == NULL) - { + if (!path_list_to_buffer(&personality->dir_list, &pc_path_buf, PKG_CONFIG_PATH_SEP_S[0]) || + !path_list_to_buffer(&personality->filter_libdirs, &pc_system_libdirs_buf, PKG_CONFIG_PATH_SEP_S[0]) || + !path_list_to_buffer(&personality->filter_includedirs, &pc_system_includedirs_buf, PKG_CONFIG_PATH_SEP_S[0])) goto error; - } - pkg_config_virtual->owner = client; - pkg_config_virtual->id = strdup("pkg-config"); - pkg_config_virtual->realname = strdup("pkg-config"); - pkg_config_virtual->description = strdup("virtual package defining pkgconf API version supported"); - pkg_config_virtual->url = strdup(PACKAGE_BUGREPORT); - pkg_config_virtual->version = strdup(PACKAGE_VERSION); - - pkgconf_tuple_add(client, &pkg_config_virtual->vars, "pc_system_libdirs", pkgconf_buffer_str_or_empty(&pc_system_libdirs_buf), false, 0); - pkgconf_tuple_add(client, &pkg_config_virtual->vars, "pc_system_includedirs", pkgconf_buffer_str_or_empty(&pc_system_includedirs_buf), false, 0); - pkgconf_tuple_add(client, &pkg_config_virtual->vars, "pc_path", pkgconf_buffer_str_or_empty(&pc_path_buf), false, 0); - - if (!pkgconf_client_preload_one(client, pkg_config_virtual)) - { + if (!register_builtin(client, "pkg-config", &pc_path_buf, &pc_system_libdirs_buf, &pc_system_includedirs_buf) || + !register_builtin(client, "pkgconf", &pc_path_buf, &pc_system_libdirs_buf, &pc_system_includedirs_buf)) goto error; - } - - pkgconf_pkg_t *pkgconf_virtual = calloc(1, sizeof(pkgconf_pkg_t)); - if (pkgconf_virtual == NULL) - { - goto error; - } - - pkgconf_virtual->owner = client; - pkgconf_virtual->id = strdup("pkgconf"); - pkgconf_virtual->realname = strdup("pkgconf"); - pkgconf_virtual->description = strdup("virtual package defining pkgconf API version supported"); - pkgconf_virtual->url = strdup(PACKAGE_BUGREPORT); - pkgconf_virtual->version = strdup(PACKAGE_VERSION); - - pkgconf_tuple_add(client, &pkgconf_virtual->vars, "pc_system_libdirs", pkgconf_buffer_str_or_empty(&pc_system_libdirs_buf), false, 0); - pkgconf_tuple_add(client, &pkgconf_virtual->vars, "pc_system_includedirs", pkgconf_buffer_str_or_empty(&pc_system_includedirs_buf), false, 0); - pkgconf_tuple_add(client, &pkgconf_virtual->vars, "pc_path", pkgconf_buffer_str_or_empty(&pc_path_buf), false, 0); - - if (!pkgconf_client_preload_one(client, pkgconf_virtual)) - { - goto error; - } error: pkgconf_buffer_finalize(&pc_path_buf); @@ -1015,13 +1017,13 @@ static void dump_personality(pkgconf_output_t *output, const pkgconf_cross_personality_t *p) { pkgconf_buffer_t pc_path_buf = PKGCONF_BUFFER_INITIALIZER; - path_list_to_buffer(&p->dir_list, &pc_path_buf, ':'); - pkgconf_buffer_t pc_system_libdirs_buf = PKGCONF_BUFFER_INITIALIZER; - path_list_to_buffer(&p->filter_libdirs, &pc_system_libdirs_buf, ':'); - pkgconf_buffer_t pc_system_includedirs_buf = PKGCONF_BUFFER_INITIALIZER; - path_list_to_buffer(&p->filter_includedirs, &pc_system_includedirs_buf, ':'); + + if (!path_list_to_buffer(&p->dir_list, &pc_path_buf, ':') || + !path_list_to_buffer(&p->filter_libdirs, &pc_system_libdirs_buf, ':') || + !path_list_to_buffer(&p->filter_includedirs, &pc_system_includedirs_buf, ':')) + goto out; pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "Triplet: %s\n", p->name); @@ -1038,6 +1040,7 @@ dump_personality(pkgconf_output_t *output, const pkgconf_cross_personality_t *p) if (p->want_default_static) pkgconf_output_fmt(output, PKGCONF_OUTPUT_STDOUT, "WantDefaultStatic: true\n"); +out: pkgconf_buffer_finalize(&pc_path_buf); pkgconf_buffer_finalize(&pc_system_libdirs_buf); pkgconf_buffer_finalize(&pc_system_includedirs_buf); @@ -1146,24 +1149,33 @@ pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_arg /* if these selectors are used, it means that we are querying metadata. * so signal to libpkgconf that we only want to walk the flattened dependency set. */ - if ((state->want_flags & PKG_MODVERSION) == PKG_MODVERSION || + const bool querying_flattened_metadata = + (state->want_flags & PKG_MODVERSION) == PKG_MODVERSION || (state->want_flags & PKG_REQUIRES) == PKG_REQUIRES || (state->want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE || (state->want_flags & PKG_PROVIDES) == PKG_PROVIDES || (state->want_flags & PKG_VARIABLES) == PKG_VARIABLES || (state->want_flags & PKG_PATH) == PKG_PATH || - state->want_variable != NULL) + state->want_variable != NULL; + + if (querying_flattened_metadata) state->maximum_traverse_depth = 1; - /* if we are asking for a variable, path or list of variables, this only makes sense + /* metadata queries only report properties of the modules the user asked about, they + * never combine those modules into a build, so 'Conflicts' rules between them are not + * relevant. see . + */ + if (querying_flattened_metadata || + (state->want_flags & PKG_DUMP_LICENSE) == PKG_DUMP_LICENSE || + (state->want_flags & PKG_DUMP_LICENSE_FILE) == PKG_DUMP_LICENSE_FILE || + (state->want_flags & PKG_DUMP_SOURCE) == PKG_DUMP_SOURCE) + want_client_flags |= PKGCONF_PKG_PKGF_SKIP_CONFLICTS; + + /* if we are asking for a path or list of variables, this only makes sense * for a single package. */ - if ((state->want_flags & PKG_VARIABLES) == PKG_VARIABLES || - (state->want_flags & PKG_PATH) == PKG_PATH || - state->want_variable != NULL) - { + if ((state->want_flags & PKG_VARIABLES) == PKG_VARIABLES || (state->want_flags & PKG_PATH) == PKG_PATH) state->maximum_package_count = 1; - } if ((state->want_flags & PKG_REQUIRES_PRIVATE) == PKG_REQUIRES_PRIVATE || (state->want_flags & PKG_CFLAGS)) @@ -1183,7 +1195,8 @@ pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_arg if ((destdir = pkgconf_client_getenv(&state->pkg_client, "DESTDIR")) != NULL) { if (!strcmp(destdir, sysroot_dir)) - want_client_flags |= PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES; + want_client_flags |= PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES | + PKGCONF_PKG_PKGF_NO_SYSROOT_INJECTION; } } @@ -1228,10 +1241,15 @@ pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_arg while (last_argc < argc && argv[last_argc]) { - if (pkgconf_buffer_len(&queryparams) > 0) - pkgconf_buffer_push_byte(&queryparams, ' '); + if ((pkgconf_buffer_len(&queryparams) > 0 && + !pkgconf_buffer_push_byte(&queryparams, ' ')) || + !pkgconf_buffer_append(&queryparams, argv[last_argc])) + { + pkgconf_buffer_finalize(&queryparams); + ret = EXIT_FAILURE; + goto out; + } - pkgconf_buffer_append(&queryparams, argv[last_argc]); last_argc++; } @@ -1269,12 +1287,25 @@ pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_arg dep->compare = compare; dep->version = strdup(target_version); + if (dep->version == NULL) + { + pkgconf_dependency_free(&deplist); + ret = EXIT_FAILURE; + goto out; + } } } PKGCONF_FOREACH_LIST_ENTRY(deplist.head, node) { pkgconf_dependency_t *dep = node->data; + + /* check if there is a limit to the number of packages allowed to be included, if so and we have hit + * the limit, stop adding packages to the queue. + */ + if (state->maximum_package_count > 0 && pkgq.length >= state->maximum_package_count) + break; + pkgconf_queue_push_dependency(&pkgq, dep); } @@ -1436,8 +1467,10 @@ pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_arg if ((state->want_flags & PKG_LIBS)) apply_libs(&state->pkg_client, &world, &target_list, 2); - pkgconf_fragment_render_buf(&target_list, &render_buf, true, state->want_render_ops, (state->want_flags & PKG_NEWLINES) ? '\n' : ' '); - pkgconf_output_putbuf(state->pkg_client.output, PKGCONF_OUTPUT_STDOUT, &render_buf, true); + if (!pkgconf_fragment_render_buf(&target_list, &render_buf, true, state->want_render_ops, + (state->want_flags & PKG_NEWLINES) ? '\n' : ' ') || + !pkgconf_output_putbuf(state->pkg_client.output, PKGCONF_OUTPUT_STDOUT, &render_buf, true)) + ret = EXIT_FAILURE; pkgconf_buffer_finalize(&render_buf); pkgconf_fragment_free(&target_list); diff --git a/contrib/pkgconf/cli/core.h b/contrib/pkgconf/cli/core.h index c6c5886e070e..badbeecfdaea 100644 --- a/contrib/pkgconf/cli/core.h +++ b/contrib/pkgconf/cli/core.h @@ -96,7 +96,7 @@ typedef struct { bool opened_error_msgout; } pkgconf_cli_state_t; -extern void path_list_to_buffer(const pkgconf_list_t *list, pkgconf_buffer_t *buffer, char delim); +extern bool path_list_to_buffer(const pkgconf_list_t *list, pkgconf_buffer_t *buffer, char delim); extern int pkgconf_cli_run(pkgconf_cli_state_t *state, int argc, char *argv[], int last_argc); extern void pkgconf_cli_state_reset(pkgconf_cli_state_t *state); diff --git a/contrib/pkgconf/cli/main.c b/contrib/pkgconf/cli/main.c index 060e54983333..6368309972ce 100644 --- a/contrib/pkgconf/cli/main.c +++ b/contrib/pkgconf/cli/main.c @@ -21,6 +21,22 @@ #include "getopt_long.h" #include "core.h" +static bool +parse_maximum_traverse_depth(const char *value, int *depth) +{ + char *end; + long parsed; + + errno = 0; + parsed = strtol(value, &end, 10); + + if (value == end || *end != '\0' || errno == ERANGE || parsed < -1 || parsed > INT_MAX) + return false; + + *depth = (int) parsed; + return true; +} + static const char * environ_lookup_handler(const pkgconf_client_t *client, const char *key) { @@ -66,7 +82,7 @@ deduce_personality(char *argv[]) if (i != NULL) argv0 = i + 1; -#if defined(_WIN32) || defined(_WIN64) +#if defined(_WIN32) || defined(_WIN64) || defined(__OS2__) i = strrchr(argv0, '\\'); if (i != NULL) argv0 = i + 1; @@ -166,7 +182,7 @@ usage(void) printf(" --uninstalled check whether or not an uninstalled module will be used\n"); printf(" --no-uninstalled never use uninstalled modules when satisfying dependencies\n"); printf(" --no-provides do not use 'provides' rules to resolve dependencies\n"); - printf(" --maximum-traverse-depth maximum allowed depth for dependency graph\n"); + printf(" --maximum-traverse-depth maximum allowed depth for dependency graph (-1 for unlimited)\n"); printf(" --static be more aggressive when computing dependency graph\n"); printf(" (for static linking)\n"); printf(" --shared use a simplified dependency graph (usually default)\n"); @@ -240,6 +256,7 @@ main(int argc, char *argv[]) int ret; pkgconf_cli_state_t state = { .want_flags = 0, + .maximum_traverse_depth = 256, }; pkgconf_list_t dir_list = PKGCONF_LIST_INITIALIZER; char *env_traverse_depth; @@ -252,7 +269,7 @@ main(int argc, char *argv[]) return EXIT_FAILURE; } -#ifdef _WIN32 +#if defined(_WIN32) || defined(__OS2__) /* When running regression tests in cygwin, and building native * executable, tests fail unless native executable outputs unix * line endings. Come to think of it, this will probably help @@ -365,7 +382,12 @@ main(int argc, char *argv[]) state.want_variable = pkg_optarg; break; case 11: - state.maximum_traverse_depth = atoi(pkg_optarg); + if (!parse_maximum_traverse_depth(pkg_optarg, &state.maximum_traverse_depth)) + { + pkgconf_output_file_fmt(stderr, "pkgconf: invalid maximum traverse depth: %s\n", pkg_optarg); + ret = EXIT_FAILURE; + goto out; + } break; case 27: pkgconf_tuple_define_global(&state.pkg_client, pkg_optarg); @@ -417,16 +439,28 @@ main(int argc, char *argv[]) } /* now, bring up the client. settings are preserved since the client is prealloced */ - pkgconf_client_init(&state.pkg_client, error_handler, &state, personality, &state, environ_lookup_handler); - pkgconf_client_set_unveil_handler(&state.pkg_client, unveil_handler); + pkgconf_client_options_t client_options = { + .error_handler = error_handler, + .error_handler_data = &state, + .personality = personality, + .client_data = &state, + .environ_lookup_handler = environ_lookup_handler, + .unveil_handler = unveil_handler, + }; + pkgconf_client_init_with_options(&state.pkg_client, &client_options); #ifndef PKGCONF_LITE if (getenv("PKG_CONFIG_MSVC_SYNTAX") != NULL) state.want_flags |= PKG_MSVC_SYNTAX; #endif - if ((env_traverse_depth = getenv("PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH")) != NULL) - state.maximum_traverse_depth = atoi(env_traverse_depth); + if ((env_traverse_depth = getenv("PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH")) != NULL && + !parse_maximum_traverse_depth(env_traverse_depth, &state.maximum_traverse_depth)) + { + pkgconf_output_file_fmt(stderr, "pkgconf: invalid maximum traverse depth: %s\n", env_traverse_depth); + ret = EXIT_FAILURE; + goto out; + } if ((state.want_flags & PKG_PRINT_ERRORS) != PKG_PRINT_ERRORS) state.want_flags |= (PKG_SILENCE_ERRORS); diff --git a/contrib/pkgconf/cli/pccritic/critic.c b/contrib/pkgconf/cli/pccritic/critic.c new file mode 100644 index 000000000000..a00215a9054e --- /dev/null +++ b/contrib/pkgconf/cli/pccritic/critic.c @@ -0,0 +1,588 @@ +/* + * pccritic/critic.c + * pc(5) quality scoring engine + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2026 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include "libpkgconf/config.h" +#include +#include +#include "critic.h" + +/* + * Each severity carries a fixed point penalty. The score begins at 100 and + * each finding subtracts its severity's penalty; the result is clamped to the + * range 0..100. Keeping the weights here makes the scoring model auditable in + * one place. + */ +static const int severity_penalty[PCCRITIC_SEV_COUNT] = { + [PCCRITIC_SEV_CRITICAL] = 25, + [PCCRITIC_SEV_MAJOR] = 10, + [PCCRITIC_SEV_MINOR] = 4, + [PCCRITIC_SEV_INFO] = 1, +}; + +static const char *severity_names[PCCRITIC_SEV_COUNT] = { + [PCCRITIC_SEV_CRITICAL] = "critical", + [PCCRITIC_SEV_MAJOR] = "major", + [PCCRITIC_SEV_MINOR] = "minor", + [PCCRITIC_SEV_INFO] = "info", +}; + +static const char *category_names[PCCRITIC_CAT_COUNT] = { + [PCCRITIC_CAT_METADATA] = "metadata", + [PCCRITIC_CAT_VERSION] = "version", + [PCCRITIC_CAT_RELOCATION] = "relocation", + [PCCRITIC_CAT_CFLAGS] = "cflags", + [PCCRITIC_CAT_LIBS] = "libs", + [PCCRITIC_CAT_REQUIRES] = "requires", + [PCCRITIC_CAT_SBOM] = "sbom", + [PCCRITIC_CAT_STYLE] = "style", +}; + +const char * +pccritic_severity_name(pccritic_severity_t severity) +{ + if (severity >= PCCRITIC_SEV_COUNT) + return "unknown"; + + return severity_names[severity]; +} + +const char * +pccritic_category_name(pccritic_category_t category) +{ + if (category >= PCCRITIC_CAT_COUNT) + return "unknown"; + + return category_names[category]; +} + +pccritic_report_t * +pccritic_report_new(void) +{ + pccritic_report_t *report = calloc(1, sizeof(*report)); + + if (report == NULL) + return NULL; + + report->score = 100; + report->grade = 'A'; + + return report; +} + +void +pccritic_report_free(pccritic_report_t *report) +{ + pkgconf_node_t *node, *tmp; + + if (report == NULL) + return; + + PKGCONF_FOREACH_LIST_ENTRY_SAFE(report->findings.head, tmp, node) + { + pccritic_finding_t *finding = node->data; + + free(finding->message); + free(finding); + } + + free(report); +} + +PRINTFLIKE(5, 6) static void +add_finding(pccritic_report_t *report, pccritic_severity_t severity, pccritic_category_t category, + const char *code, const char *fmt, ...) +{ + pccritic_finding_t *finding; + va_list va; + char buf[1024]; + + finding = calloc(1, sizeof(*finding)); + if (finding == NULL) + return; + + va_start(va, fmt); + vsnprintf(buf, sizeof buf, fmt, va); + va_end(va); + + finding->severity = severity; + finding->category = category; + finding->code = code; + finding->message = strdup(buf); + + if (finding->message == NULL) + { + free(finding); + return; + } + + report->counts[severity]++; + pkgconf_node_insert_tail(&finding->iter, finding, &report->findings); +} + +static bool +str_empty(const char *s) +{ + return s == NULL || *s == '\0'; +} + +/* ------------------------------------------------------------------------ */ + +static void +check_metadata(pkgconf_pkg_t *pkg, pccritic_report_t *report) +{ + if (str_empty(pkg->realname)) + add_finding(report, PCCRITIC_SEV_CRITICAL, PCCRITIC_CAT_METADATA, "PC001", + "missing required 'Name:' field"); + + if (str_empty(pkg->version)) + add_finding(report, PCCRITIC_SEV_CRITICAL, PCCRITIC_CAT_METADATA, "PC002", + "missing required 'Version:' field"); + + if (str_empty(pkg->description)) + add_finding(report, PCCRITIC_SEV_MAJOR, PCCRITIC_CAT_METADATA, "PC003", + "missing required 'Description:' field"); + else if (strlen(pkg->description) < 12) + add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_METADATA, "PC004", + "'Description:' is very terse (\"%s\")", pkg->description); + + if (str_empty(pkg->url)) + add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_METADATA, "PC005", + "missing recommended 'URL:' field"); +} + +static void +check_version(pkgconf_pkg_t *pkg, pccritic_report_t *report) +{ + const char *p; + bool has_digit = false, has_space = false; + + if (str_empty(pkg->version)) + return; /* already reported as PC002 */ + + for (p = pkg->version; *p != '\0'; p++) + { + if (*p >= '0' && *p <= '9') + has_digit = true; + if (*p == ' ' || *p == '\t') + has_space = true; + } + + if (has_space) + add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_VERSION, "PC011", + "'Version:' contains whitespace (\"%s\")", pkg->version); + + if (!has_digit) + add_finding(report, PCCRITIC_SEV_MAJOR, PCCRITIC_CAT_VERSION, "PC010", + "'Version:' has no numeric component (\"%s\")", pkg->version); +} + +static bool +var_relocatable(pkgconf_pkg_t *pkg, const char *name) +{ + pkgconf_variable_t *v = pkgconf_variable_find(&pkg->vars, name); + + if (v == NULL) + return true; /* not present: not our concern here */ + + return pkgconf_bytecode_references_var(&v->bcbuf, "prefix") || + pkgconf_bytecode_references_var(&v->bcbuf, "exec_prefix"); +} + +static void +check_relocation(pkgconf_pkg_t *pkg, pccritic_report_t *report) +{ + bool has_prefix = pkgconf_variable_find(&pkg->vars, "prefix") != NULL; + + if (!has_prefix) + add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_RELOCATION, "PC020", + "no 'prefix' variable is defined; the package cannot be relocated"); + + if (pkgconf_variable_find(&pkg->vars, "libdir") != NULL && !var_relocatable(pkg, "libdir")) + add_finding(report, PCCRITIC_SEV_MAJOR, PCCRITIC_CAT_RELOCATION, "PC021", + "'libdir' is hardcoded; derive it from ${prefix} or ${exec_prefix} for relocatability"); + + if (pkgconf_variable_find(&pkg->vars, "includedir") != NULL && !var_relocatable(pkg, "includedir")) + add_finding(report, PCCRITIC_SEV_MAJOR, PCCRITIC_CAT_RELOCATION, "PC022", + "'includedir' is hardcoded; derive it from ${prefix} for relocatability"); +} + +/* Reconstruct a fragment's textual flag form for diagnostics. */ +static const char * +fragment_text(const pkgconf_fragment_t *frag, char *buf, size_t buflen) +{ + if (frag->type != 0) + snprintf(buf, buflen, "-%c%s", frag->type, frag->data != NULL ? frag->data : ""); + else + snprintf(buf, buflen, "%s", frag->data != NULL ? frag->data : ""); + + return buf; +} + +static bool +prefix_match(const char *s, const char *prefix) +{ + size_t n = strlen(prefix); + return strncmp(s, prefix, n) == 0; +} + +/* Well-known directories already on the compiler/linker default search path. */ +static bool +is_system_includedir(const char *path) +{ +#ifdef SYSTEM_INCLUDEDIR + if (!strcmp(path, SYSTEM_INCLUDEDIR)) + return true; +#endif + return !strcmp(path, "/usr/include") || !strcmp(path, "/usr/local/include"); +} + +static bool +is_system_libdir(const char *path) +{ +#ifdef SYSTEM_LIBDIR + if (!strcmp(path, SYSTEM_LIBDIR)) + return true; +#endif + return !strcmp(path, "/usr/lib") || !strcmp(path, "/usr/lib64") || + !strcmp(path, "/lib") || !strcmp(path, "/lib64") || + !strcmp(path, "/usr/local/lib"); +} + +static void +check_cflags(pkgconf_pkg_t *pkg, pccritic_report_t *report) +{ + pkgconf_node_t *node; + char buf[PKGCONF_BUFSIZE]; + + PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags.head, node) + { + pkgconf_fragment_t *frag = node->data; + + switch (frag->type) + { + case 'I': + if (frag->data != NULL && is_system_includedir(frag->data)) + add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_CFLAGS, "PC031", + "Cflags adds an include path already on the default search path (pkgconf strips it): -I%s", frag->data); + break; + case 'D': + case 'U': + case 'F': /* -F: framework search dir (Darwin) */ + break; + case 0: + /* raw / unmergeable flag: classify by content */ + if (frag->data == NULL) + break; + if (!strcmp(frag->data, "-pthread") || + prefix_match(frag->data, "-isystem") || + prefix_match(frag->data, "-idirafter") || + prefix_match(frag->data, "-iquote") || + prefix_match(frag->data, "-imacros") || + prefix_match(frag->data, "-include") || + prefix_match(frag->data, "-framework")) + break; + if (prefix_match(frag->data, "-std=") || prefix_match(frag->data, "-stdlib=")) + add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_CFLAGS, "PC033", + "Cflags imposes a language standard on consumers: %s", frag->data); + else if (prefix_match(frag->data, "-Wl,")) + add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_CFLAGS, "PC032", + "Cflags contains a linker flag, which belongs in Libs: %s", frag->data); + else + add_finding(report, PCCRITIC_SEV_MAJOR, PCCRITIC_CAT_CFLAGS, "PC030", + "Cflags contains a build-tuning flag that pollutes consumer builds: %s", frag->data); + break; + case 'l': + case 'L': + add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_CFLAGS, "PC034", + "Cflags contains a linker flag, which belongs in Libs: %s", + fragment_text(frag, buf, sizeof buf)); + break; + default: + add_finding(report, PCCRITIC_SEV_MAJOR, PCCRITIC_CAT_CFLAGS, "PC030", + "Cflags contains a build-tuning flag that pollutes consumer builds: %s", + fragment_text(frag, buf, sizeof buf)); + break; + } + } +} + +static void +check_libs_list(pkgconf_list_t *libs, const char *which, pccritic_report_t *report) +{ + pkgconf_node_t *node; + char buf[PKGCONF_BUFSIZE]; + + PKGCONF_FOREACH_LIST_ENTRY(libs->head, node) + { + pkgconf_fragment_t *frag = node->data; + + switch (frag->type) + { + case 'l': + break; + case 'L': + if (frag->data != NULL && is_system_libdir(frag->data)) + add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_LIBS, "PC040", + "%s adds a library path already on the default search path (pkgconf strips it): -L%s", which, frag->data); + break; + case 'F': /* -F framework dir / -framework arrives as type 0 */ + break; + case 0: + if (frag->data == NULL) + break; + if (strstr(frag->data, "-rpath") != NULL || strstr(frag->data, "rpath=") != NULL) + add_finding(report, PCCRITIC_SEV_MAJOR, PCCRITIC_CAT_LIBS, "PC042", + "%s hardcodes a runtime library path: %s", which, frag->data); + else if (!strcmp(frag->data, "-pthread") || + prefix_match(frag->data, "-framework") || + prefix_match(frag->data, "-Wl,") || + prefix_match(frag->data, "-l")) + break; + else + add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_LIBS, "PC041", + "%s contains an unexpected flag: %s", which, frag->data); + break; + default: + add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_LIBS, "PC041", + "%s contains an unexpected flag: %s", which, fragment_text(frag, buf, sizeof buf)); + break; + } + } +} + +static void +check_libs(pkgconf_pkg_t *pkg, pccritic_report_t *report) +{ + check_libs_list(&pkg->libs, "Libs", report); + check_libs_list(&pkg->libs_private, "Libs.private", report); +} + +static bool +dep_in_list(pkgconf_list_t *list, const char *package) +{ + pkgconf_node_t *node; + + PKGCONF_FOREACH_LIST_ENTRY(list->head, node) + { + pkgconf_dependency_t *dep = node->data; + + if (dep->package != NULL && !strcmp(dep->package, package)) + return true; + } + + return false; +} + +static void +check_requires(pkgconf_pkg_t *pkg, pccritic_report_t *report) +{ + pkgconf_node_t *node; + + PKGCONF_FOREACH_LIST_ENTRY(pkg->required.head, node) + { + pkgconf_dependency_t *dep = node->data; + + if (dep->package != NULL && dep_in_list(&pkg->requires_private, dep->package)) + add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_REQUIRES, "PC051", + "'%s' appears in both Requires and Requires.private", dep->package); + } +} + +/* + * The NTIA "minimum elements" for an SBOM are: supplier name, component name, + * component version, other unique identifiers, dependency relationships, + * author of the SBOM data, and a timestamp. Component name and version are + * the required pc(5) fields (PC001/PC002) and dependency relationships are the + * Requires fields, so they are covered elsewhere; author and timestamp are + * supplied by the SBOM generator (bomtool/spdxtool) rather than the .pc file. + * This leaves the supplier and a provenance identifier, both of which map to + * optional pkgconf fields that the SBOM tooling consumes. + */ +static void +check_sbom(pkgconf_pkg_t *pkg, pccritic_report_t *report) +{ + if (str_empty(pkg->maintainer)) + add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_SBOM, "PC070", + "missing 'Maintainer:' field; the NTIA SBOM supplier name cannot be determined"); + + if (str_empty(pkg->source)) + add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_SBOM, "PC071", + "missing 'Source:' field; an SBOM has no download location for this package"); + + if (pkg->license.head == NULL) + add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_SBOM, "PC072", + "missing 'License:' field; an SBOM cannot record a declared license"); +} + +static void +check_style(const char *path, pccritic_report_t *report) +{ + FILE *f; + int c, prev = '\n'; + bool saw_trailing_ws = false, saw_bom = false; + long pos = 0; + + if (path == NULL) + return; + + f = fopen(path, "rb"); + if (f == NULL) + return; + + while ((c = fgetc(f)) != EOF) + { + if (pos < 3) + { + static const unsigned char bom[3] = { 0xEF, 0xBB, 0xBF }; + if ((unsigned char) c == bom[pos]) + { + if (pos == 2) + saw_bom = true; + } + else + pos = 3; /* not a BOM; stop checking */ + } + + if (c == '\n' && (prev == ' ' || prev == '\t')) + saw_trailing_ws = true; + + prev = c; + pos++; + } + + fclose(f); + + if (saw_bom) + add_finding(report, PCCRITIC_SEV_MINOR, PCCRITIC_CAT_STYLE, "PC060", + "file begins with a UTF-8 byte-order mark"); + + if (saw_trailing_ws) + add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_STYLE, "PC062", + "file has trailing whitespace on one or more lines"); + + if (pos > 0 && prev != '\n') + add_finding(report, PCCRITIC_SEV_INFO, PCCRITIC_CAT_STYLE, "PC063", + "file does not end with a newline"); +} + +static void +finalize_score(pccritic_report_t *report) +{ + int penalty = 0; + pccritic_severity_t sev; + + for (sev = 0; sev < PCCRITIC_SEV_COUNT; sev++) + penalty += (int) report->counts[sev] * severity_penalty[sev]; + + report->score = 100 - penalty; + if (report->score < 0) + report->score = 0; + + if (report->score >= 90) + report->grade = 'A'; + else if (report->score >= 80) + report->grade = 'B'; + else if (report->score >= 70) + report->grade = 'C'; + else if (report->score >= 60) + report->grade = 'D'; + else + report->grade = 'F'; +} + +void +pccritic_analyze(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pccritic_report_t *report) +{ + (void) client; + + check_metadata(pkg, report); + check_version(pkg, report); + check_relocation(pkg, report); + check_cflags(pkg, report); + check_libs(pkg, report); + check_requires(pkg, report); + check_sbom(pkg, report); + check_style(pkg->filename, report); + + finalize_score(report); +} + +/* Does the file declare `key:' at the start of any logical line? */ +static bool +file_declares_field(FILE *f, const char *key) +{ + char line[PKGCONF_BUFSIZE]; + size_t keylen = strlen(key); + + rewind(f); + + while (fgets(line, sizeof line, f) != NULL) + { + const char *p = line; + + while (*p == ' ' || *p == '\t') + p++; + + if (!strncmp(p, key, keylen)) + { + p += keylen; + while (*p == ' ' || *p == '\t') + p++; + if (*p == ':') + return true; + } + } + + return false; +} + +void +pccritic_analyze_unparsable(pccritic_report_t *report, const char *path) +{ + static const struct { + const char *field; + const char *code; + } required[] = { + { "Name", "PC001" }, + { "Version", "PC002" }, + { "Description", "PC003" }, + }; + FILE *f = fopen(path, "rb"); + size_t i; + + if (f == NULL) + { + add_finding(report, PCCRITIC_SEV_CRITICAL, PCCRITIC_CAT_METADATA, "PC000", + "file could not be read"); + finalize_score(report); + return; + } + + for (i = 0; i < PKGCONF_ARRAY_SIZE(required); i++) + if (!file_declares_field(f, required[i].field)) + add_finding(report, PCCRITIC_SEV_CRITICAL, PCCRITIC_CAT_METADATA, required[i].code, + "missing required '%s:' field", required[i].field); + + fclose(f); + + if (report->findings.head == NULL) + add_finding(report, PCCRITIC_SEV_CRITICAL, PCCRITIC_CAT_METADATA, "PC000", + "file is not a valid pc(5) file"); + + check_style(path, report); + finalize_score(report); +} diff --git a/contrib/pkgconf/cli/pccritic/critic.h b/contrib/pkgconf/cli/pccritic/critic.h new file mode 100644 index 000000000000..32020819773b --- /dev/null +++ b/contrib/pkgconf/cli/pccritic/critic.h @@ -0,0 +1,81 @@ +/* + * pccritic/critic.h + * pc(5) quality scoring engine + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2026 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#ifndef PCCRITIC_CRITIC_H +#define PCCRITIC_CRITIC_H + +#include + +typedef enum { + PCCRITIC_SEV_CRITICAL = 0, + PCCRITIC_SEV_MAJOR, + PCCRITIC_SEV_MINOR, + PCCRITIC_SEV_INFO, + PCCRITIC_SEV_COUNT +} pccritic_severity_t; + +typedef enum { + PCCRITIC_CAT_METADATA = 0, + PCCRITIC_CAT_VERSION, + PCCRITIC_CAT_RELOCATION, + PCCRITIC_CAT_CFLAGS, + PCCRITIC_CAT_LIBS, + PCCRITIC_CAT_REQUIRES, + PCCRITIC_CAT_SBOM, + PCCRITIC_CAT_STYLE, + PCCRITIC_CAT_COUNT +} pccritic_category_t; + +typedef struct { + pkgconf_node_t iter; + + pccritic_severity_t severity; + pccritic_category_t category; + const char *code; + char *message; +} pccritic_finding_t; + +typedef struct { + pkgconf_list_t findings; + + unsigned int counts[PCCRITIC_SEV_COUNT]; + + int score; /* 0..100 */ + char grade; /* 'A'..'F' */ +} pccritic_report_t; + +pccritic_report_t *pccritic_report_new(void); +void pccritic_report_free(pccritic_report_t *report); + +/* + * Analyze a parsed package, appending findings to the report and computing + * its score and letter grade. The package must already have been loaded via + * pkgconf_pkg_new_from_path() or pkgconf_pkg_find(). + */ +void pccritic_analyze(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pccritic_report_t *report); + +/* + * Analyze a .pc file that libpkgconf refused to load (typically because it is + * missing one of the required Name/Description/Version fields). The raw file + * is scanned directly so that the most broken files can still be scored. + */ +void pccritic_analyze_unparsable(pccritic_report_t *report, const char *path); + +const char *pccritic_severity_name(pccritic_severity_t severity); +const char *pccritic_category_name(pccritic_category_t category); + +#endif /* PCCRITIC_CRITIC_H */ diff --git a/contrib/pkgconf/cli/pccritic/main.c b/contrib/pkgconf/cli/pccritic/main.c new file mode 100644 index 000000000000..5d7e4d84e732 --- /dev/null +++ b/contrib/pkgconf/cli/pccritic/main.c @@ -0,0 +1,422 @@ +/* + * pccritic/main.c + * pc(5) quality scorer + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2026 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include "libpkgconf/config.h" +#include +#include +#include "getopt_long.h" +#include "critic.h" + +#define PKG_VERSION (((uint64_t) 1) << 1) +#define PKG_ABOUT (((uint64_t) 1) << 2) +#define PKG_HELP (((uint64_t) 1) << 3) + +#define PKG_QUIET 100 +#define PKG_MIN_SCORE 101 +#define PKG_DEFINE_VARIABLE 102 +#define PKG_COLOR 103 + +#define ANSI_RESET "\033[0m" +#define ANSI_DIM "\033[2m" + +typedef enum { + COLOR_AUTO = 0, + COLOR_ALWAYS, + COLOR_NEVER, +} color_mode_t; + +static pkgconf_client_t pkg_client; +static uint64_t want_flags; +static bool opt_quiet = false; +static int opt_min_score = -1; +static color_mode_t opt_color = COLOR_AUTO; +static bool color_on = false; +static FILE *out = NULL; +static FILE *error_msgout = NULL; + +static bool +parse_min_score(const char *value, int *score) +{ + char *end; + long parsed; + + errno = 0; + parsed = strtol(value, &end, 10); + + if (value == end || *end != '\0' || errno == ERANGE || parsed < 0 || parsed > 100) + return false; + + *score = (int) parsed; + return true; +} + +static void +resolve_color(void) +{ + switch (opt_color) + { + case COLOR_ALWAYS: + color_on = true; + break; + case COLOR_NEVER: + color_on = false; + break; + case COLOR_AUTO: + default: + color_on = isatty(fileno(out)) && getenv("NO_COLOR") == NULL; + break; + } +} + +static const char * +severity_color(pccritic_severity_t severity) +{ + if (!color_on) + return ""; + + switch (severity) + { + case PCCRITIC_SEV_CRITICAL: return "\033[1;31m"; /* bold red */ + case PCCRITIC_SEV_MAJOR: return "\033[31m"; /* red */ + case PCCRITIC_SEV_MINOR: return "\033[33m"; /* yellow */ + case PCCRITIC_SEV_INFO: return "\033[36m"; /* cyan */ + default: return ""; + } +} + +static const char * +grade_color(char grade) +{ + if (!color_on) + return ""; + + switch (grade) + { + case 'A': + case 'B': return "\033[32m"; /* green */ + case 'C': + case 'D': return "\033[33m"; /* yellow */ + default: return "\033[1;31m"; /* bold red */ + } +} + +static const char * +dim(void) +{ + return color_on ? ANSI_DIM : ""; +} + +static const char * +reset(void) +{ + return color_on ? ANSI_RESET : ""; +} + +static const char * +environ_lookup_handler(const pkgconf_client_t *client, const char *key) +{ + (void) client; + return getenv(key); +} + +static bool +error_handler(const char *msg, const pkgconf_client_t *client, void *data) +{ + (void) client; + (void) data; + return pkgconf_output_file_fmt(error_msgout, "%s", msg); +} + +/* pccritic emits its own findings; swallow libpkgconf's own warnings so they + * do not interleave with the report. + */ +static bool +silent_handler(const char *msg, const pkgconf_client_t *client, void *data) +{ + (void) msg; + (void) client; + (void) data; + return true; +} + +static int +version(void) +{ + printf("pccritic %s\n", PACKAGE_VERSION); + return EXIT_SUCCESS; +} + +static int +about(void) +{ + printf("pccritic (%s %s)\n", PACKAGE_NAME, PACKAGE_VERSION); + printf("Copyright (c) 2011-2026 pkgconf authors (see AUTHORS in documentation directory)\n\n"); + printf("Permission to use, copy, modify, and/or distribute this software for any\n"); + printf("purpose with or without fee is hereby granted, provided that the above\n"); + printf("copyright notice and this permission notice appear in all copies.\n\n"); + printf("This software is provided 'as is' and without any warranty, express or\n"); + printf("implied. In no event shall the authors be liable for any damages arising\n"); + printf("from the use of this software.\n\n"); + printf("Report bugs at <%s>.\n", PACKAGE_BUGREPORT); + return EXIT_SUCCESS; +} + +static int +usage(void) +{ + printf("usage: pccritic [--flags] [module-or-file ...]\n"); + + printf("\npccritic scores the quality of pkg-config (pc(5)) files. Each argument\n"); + printf("is either a module name resolved from the search path, or a path to a\n"); + printf(".pc file. Findings are reported and the file is graded from A to F.\n"); + + printf("\nbasic options:\n\n"); + + printf(" --help this message\n"); + printf(" --about print pccritic version and license to stdout\n"); + printf(" --version print pccritic version to stdout\n"); + printf(" --quiet print only the score and grade per target\n"); + printf(" --min-score N exit non-zero if any target scores below N\n"); + printf(" --color[=WHEN] colorize output; WHEN is 'auto', 'always' or 'never'\n"); + printf(" --define-variable=varname=value define variable 'varname' as 'value'\n"); + + return EXIT_SUCCESS; +} + +static bool +ends_with(const char *str, const char *suffix) +{ + size_t slen = strlen(str), xlen = strlen(suffix); + + return slen >= xlen && strcmp(str + slen - xlen, suffix) == 0; +} + +static bool +looks_like_path(const char *arg) +{ + return strchr(arg, '/') != NULL || ends_with(arg, ".pc"); +} + +static bool +file_readable(const char *path) +{ + FILE *f = fopen(path, "rb"); + + if (f == NULL) + return false; + + fclose(f); + return true; +} + +static pkgconf_pkg_t * +resolve_target(pkgconf_client_t *client, const char *arg) +{ + if (looks_like_path(arg)) + return pkgconf_pkg_new_from_path(client, arg, 0); + + return pkgconf_pkg_find(client, arg); +} + +static void +render_report(const char *target, pkgconf_pkg_t *pkg, pccritic_report_t *report) +{ + pkgconf_node_t *node; + + if (opt_quiet) + { + pkgconf_output_file_fmt(out, "%s: %d/100 %s(%c)%s\n", + target, report->score, grade_color(report->grade), report->grade, reset()); + return; + } + + pkgconf_output_file_fmt(out, "%s\n", target); + if (pkg != NULL && pkg->filename != NULL && strcmp(pkg->filename, target) != 0) + pkgconf_output_file_fmt(out, " file: %s\n", pkg->filename); + + pkgconf_output_file_fmt(out, " score: %d/100 grade: %s%c%s %s(%u critical, %u major, %u minor, %u info)%s\n", + report->score, grade_color(report->grade), report->grade, reset(), + dim(), + report->counts[PCCRITIC_SEV_CRITICAL], report->counts[PCCRITIC_SEV_MAJOR], + report->counts[PCCRITIC_SEV_MINOR], report->counts[PCCRITIC_SEV_INFO], + reset()); + + if (report->findings.head == NULL) + { + pkgconf_output_file_fmt(out, " no issues found.\n\n"); + return; + } + + PKGCONF_FOREACH_LIST_ENTRY(report->findings.head, node) + { + pccritic_finding_t *finding = node->data; + + pkgconf_output_file_fmt(out, " %s[%-8s]%s %s %s(%s/%s)%s\n", + severity_color(finding->severity), pccritic_severity_name(finding->severity), reset(), + finding->message, + dim(), pccritic_category_name(finding->category), finding->code, reset()); + } + + pkgconf_output_file_fmt(out, "\n"); +} + +int +main(int argc, char *argv[]) +{ + int ret = EXIT_SUCCESS; + int exit_code = EXIT_SUCCESS; + unsigned int want_client_flags = PKGCONF_PKG_PKGF_SEARCH_PRIVATE | PKGCONF_PKG_PKGF_SKIP_ERRORS; + pkgconf_cross_personality_t *personality = pkgconf_cross_personality_default(); + + out = stdout; + error_msgout = stderr; + + struct pkg_option options[] = { + { "version", no_argument, &want_flags, PKG_VERSION, }, + { "about", no_argument, &want_flags, PKG_ABOUT, }, + { "help", no_argument, &want_flags, PKG_HELP, }, + { "quiet", no_argument, NULL, PKG_QUIET, }, + { "min-score", required_argument, NULL, PKG_MIN_SCORE, }, + { "color", optional_argument, NULL, PKG_COLOR, }, + { "define-variable", required_argument, NULL, PKG_DEFINE_VARIABLE, }, + { NULL, 0, NULL, 0 } + }; + + while ((ret = pkg_getopt_long_only(argc, argv, "", options, NULL)) != -1) + { + switch (ret) + { + case PKG_QUIET: + opt_quiet = true; + break; + case PKG_MIN_SCORE: + if (!parse_min_score(pkg_optarg, &opt_min_score)) + { + pkgconf_output_file_fmt(error_msgout, + "pccritic: invalid --min-score value '%s' (use 0 through 100)\n", + pkg_optarg); + return EXIT_FAILURE; + } + break; + case PKG_COLOR: + if (pkg_optarg == NULL || !strcmp(pkg_optarg, "always")) + opt_color = COLOR_ALWAYS; + else if (!strcmp(pkg_optarg, "never")) + opt_color = COLOR_NEVER; + else if (!strcmp(pkg_optarg, "auto")) + opt_color = COLOR_AUTO; + else + { + pkgconf_output_file_fmt(error_msgout, "pccritic: invalid --color value '%s' (use auto, always or never)\n", pkg_optarg); + return EXIT_FAILURE; + } + break; + case PKG_DEFINE_VARIABLE: + pkgconf_tuple_define_global(&pkg_client, pkg_optarg); + break; + case '?': + case ':': + return EXIT_FAILURE; + default: + break; + } + } + + pkgconf_client_options_t client_options = { + .error_handler = error_handler, + .personality = personality, + .environ_lookup_handler = environ_lookup_handler, + }; + pkgconf_client_init_with_options(&pkg_client, &client_options); + + pkgconf_client_set_warn_handler(&pkg_client, silent_handler, NULL); + pkgconf_client_set_flags(&pkg_client, want_client_flags); + pkgconf_client_dir_list_build(&pkg_client, personality); + + if ((want_flags & PKG_ABOUT) == PKG_ABOUT) + { + exit_code = about(); + goto out; + } + + if ((want_flags & PKG_VERSION) == PKG_VERSION) + { + exit_code = version(); + goto out; + } + + if ((want_flags & PKG_HELP) == PKG_HELP) + { + exit_code = usage(); + goto out; + } + + if (pkg_optind >= argc || argv[pkg_optind] == NULL) + { + pkgconf_output_file_fmt(error_msgout, "pccritic: please specify at least one module name or .pc file\n"); + exit_code = EXIT_FAILURE; + goto out; + } + + resolve_color(); + + for (; pkg_optind < argc && argv[pkg_optind] != NULL; pkg_optind++) + { + const char *target = argv[pkg_optind]; + pkgconf_pkg_t *pkg; + pccritic_report_t *report; + + pkg = resolve_target(&pkg_client, target); + + if (pkg == NULL && !(looks_like_path(target) && file_readable(target))) + { + pkgconf_output_file_fmt(error_msgout, "pccritic: could not load '%s'\n", target); + exit_code = EXIT_FAILURE; + continue; + } + + report = pccritic_report_new(); + if (report == NULL) + { + if (pkg != NULL) + pkgconf_pkg_unref(&pkg_client, pkg); + pkgconf_output_file_fmt(error_msgout, "pccritic: out of memory\n"); + exit_code = EXIT_FAILURE; + goto out; + } + + if (pkg != NULL) + pccritic_analyze(&pkg_client, pkg, report); + else + pccritic_analyze_unparsable(report, target); + + render_report(target, pkg, report); + + if (opt_min_score >= 0 && report->score < opt_min_score) + exit_code = EXIT_FAILURE; + + pccritic_report_free(report); + if (pkg != NULL) + pkgconf_pkg_unref(&pkg_client, pkg); + } + +out: + pkgconf_cross_personality_deinit(personality); + pkgconf_client_deinit(&pkg_client); + + return exit_code; +} diff --git a/contrib/pkgconf/cli/renderer-msvc.c b/contrib/pkgconf/cli/renderer-msvc.c index 07c9ccf7f5b0..24404a47c5e1 100644 --- a/contrib/pkgconf/cli/renderer-msvc.c +++ b/contrib/pkgconf/cli/renderer-msvc.c @@ -50,41 +50,50 @@ allowed_fragment(const pkgconf_fragment_t *frag) return !(!frag->type || frag->data == NULL || strchr("DILl", frag->type) == NULL); } -static void +static bool msvc_renderer_render(const pkgconf_fragment_render_ctx_t *ctx, const pkgconf_fragment_t *frag, pkgconf_buffer_t *buf) { pkgconf_buffer_t tmpbuf = PKGCONF_BUFFER_INITIALIZER; bool escape = ctx->escape; if (!allowed_fragment(frag)) - return; + return true; switch(frag->type) { case 'D': case 'I': - pkgconf_buffer_append_fmt(buf, "/%c", frag->type); + if (!pkgconf_buffer_push_byte(buf, '/') || !pkgconf_buffer_push_byte(buf, frag->type)) + return false; break; case 'L': - pkgconf_buffer_append(buf, "/libpath:"); + if (!pkgconf_buffer_append(buf, "/libpath:")) + return false; break; } - pkgconf_buffer_append(&tmpbuf, frag->data); + if (!pkgconf_buffer_append(&tmpbuf, frag->data)) + return false; - if (frag->type == 'l') - pkgconf_buffer_append(&tmpbuf, ".lib"); + if (frag->type == 'l' && !pkgconf_buffer_append(&tmpbuf, ".lib")) + goto fail; escape = should_quote(&tmpbuf); - if (escape) - pkgconf_buffer_push_byte(buf, '"'); + if (escape && !pkgconf_buffer_push_byte(buf, '"')) + goto fail; - pkgconf_buffer_append(buf, pkgconf_buffer_str_or_empty(&tmpbuf)); + if (!pkgconf_buffer_append(buf, pkgconf_buffer_str_or_empty(&tmpbuf))) + goto fail; - if (escape) - pkgconf_buffer_push_byte(buf, '"'); + if (escape && !pkgconf_buffer_push_byte(buf, '"')) + goto fail; pkgconf_buffer_finalize(&tmpbuf); + return true; + +fail: + pkgconf_buffer_finalize(&tmpbuf); + return false; } static pkgconf_fragment_render_ops_t msvc_renderer_ops = { diff --git a/contrib/pkgconf/cli/spdxtool/core.c b/contrib/pkgconf/cli/spdxtool/core.c index 62268b1b10a2..94e641250379 100644 --- a/contrib/pkgconf/cli/spdxtool/core.c +++ b/contrib/pkgconf/cli/spdxtool/core.c @@ -124,6 +124,116 @@ err: return ret; } +/* + * !doc + * + * .. c:function:: spdxtool_core_tool_t *spdxtool_core_tool_new(pkgconf_client_t *client, const char *creation_info_id, const char *short_name, const char *name) + * + * Create new /Core/Tool struct + * + * :param pkgconf_client_t *client: The pkgconf client being accessed. + * :param char *creation_info_id: CreationInfo spdxId + * :param char *short_name Shorter name for tool used in SPDX id (default: 'spdxtool') + * :param char *name: Long name of tool (default: 'spdxtool') + * :return: NULL if some problem occurs and Tool struct if not + */ +spdxtool_core_tool_t * +spdxtool_core_tool_new(pkgconf_client_t *client, const char *creation_info_id, const char *short_name, const char *name) +{ + if (!client || !creation_info_id || !name) + return NULL; + + spdxtool_core_tool_t *tool = calloc(1, sizeof(spdxtool_core_tool_t)); + if (!tool) + goto err; + + tool->type = "Tool"; + + char *spdx_id_name = strdup(short_name); + if (!spdx_id_name) + goto err; + + spdxtool_util_string_correction(spdx_id_name); + + tool->spdx_id = spdxtool_util_get_spdx_id_string(client, tool->type, spdx_id_name); + free(spdx_id_name); + + tool->creation_info = strdup(creation_info_id); + tool->name = strdup(name); + + if (!tool->spdx_id || !tool->creation_info || !tool->name) + goto err; + + return tool; + + err: + pkgconf_error(client, "spdxtool_core_agent_new: out of memory"); + spdxtool_core_tool_free(tool); + return NULL; +} + +/* + * !doc + * + * .. c:function:: void spdxtool_core_tool_free(spdxtool_core_tool_t *tool) + * + * Free /Core/Tool struct + * + * :param spdxtool_core_tool_t *tool: Tool struct to be freed. + * :return: nothing + */ +void +spdxtool_core_tool_free(spdxtool_core_tool_t *tool) +{ + if (!tool) + return; + + free(tool->creation_info); + free(tool->spdx_id); + free(tool->name); + + free(tool); +} + +/* + * !doc + * + * .. c:function:: spdxtool_serialize_value_t *spdxtool_core_tool_to_object(pkgconf_client_t *client, const spdxtool_core_tool_t *tool) + * + * Serialize /Core/Tool struct to a JSON value tree. + * + * :param pkgconf_client_t *client: The pkgconf client being accessed. + * :param const spdxtool_core_tool_t *tool: Tool struct to be serialized. + * :return: spdxtool_serialize_value_t * representing the Agent object. + */ +spdxtool_serialize_value_t * +spdxtool_core_tool_to_object(pkgconf_client_t *client, const spdxtool_core_tool_t *tool) +{ + spdxtool_serialize_value_t *ret = NULL; + spdxtool_serialize_object_list_t *object_list = spdxtool_serialize_object_list_new(); + if (!object_list) + goto err; + + if (!(spdxtool_serialize_object_add_string(object_list, "type", tool->type) && + spdxtool_serialize_object_add_string(object_list, "creationInfo", tool->creation_info) && + spdxtool_serialize_object_add_string(object_list, "spdxId", tool->spdx_id) && + spdxtool_serialize_object_add_string(object_list, "name", tool->name))) + { + goto err; + } + + ret = spdxtool_serialize_value_object(object_list); + object_list = NULL; + + err: + if (!ret) + pkgconf_error(client, "spdxtool_core_agent_to_object: out of memory"); + + spdxtool_serialize_object_list_free(object_list); + return ret; +} + + /* * !doc * @@ -140,9 +250,9 @@ err: * :return: NULL if some problem occurs and CreationInfo struct if not */ spdxtool_core_creation_info_t * -spdxtool_core_creation_info_new(pkgconf_client_t *client, const char *agent_id, const char *id, const char *time) +spdxtool_core_creation_info_new(pkgconf_client_t *client, const char *agent_id, const char *tool_id, const char *id, const char *time) { - if (!client || !agent_id || !id) + if (!client || !agent_id || !id || !tool_id) return NULL; spdxtool_core_creation_info_t *creation = calloc(1, sizeof(spdxtool_core_creation_info_t)); @@ -154,9 +264,10 @@ spdxtool_core_creation_info_new(pkgconf_client_t *client, const char *agent_id, creation->id = strdup(id); creation->created = time ? strdup(time) : spdxtool_util_get_current_iso8601_time(); creation->created_by = strdup(agent_id); + creation->created_using = strdup(tool_id); creation->spec_version = strdup(spdxtool_util_get_spdx_version(client)); - if (!creation->id || !creation->created || !creation->created_by || !creation->spec_version) + if (!creation->id || !creation->created || !creation->created_by || !creation->created_using | !creation->spec_version) goto err; return creation; @@ -186,6 +297,7 @@ spdxtool_core_creation_info_free(spdxtool_core_creation_info_t *creation) free(creation->id); free(creation->created); free(creation->created_by); + free(creation->created_using); free(creation->spec_version); free(creation); @@ -220,17 +332,39 @@ spdxtool_core_creation_info_to_object(pkgconf_client_t *client, const spdxtool_c goto err; } - if (!(spdxtool_serialize_object_add_string(object_list, "type", creation->type) && - spdxtool_serialize_object_add_string(object_list, "@id", creation->id) && - spdxtool_serialize_object_add_string(object_list, "created", creation->created))) + spdxtool_serialize_array_t *created_using = spdxtool_serialize_array_new(); + if (!created_using) { - /* created_by has not been handed to the object list yet */ spdxtool_serialize_array_free(created_by); goto err; } + if (!spdxtool_serialize_array_add_string(created_using, creation->created_using)) + { + spdxtool_serialize_array_free(created_by); + spdxtool_serialize_array_free(created_using); + goto err; + } + + if (!(spdxtool_serialize_object_add_string(object_list, "type", creation->type) && + spdxtool_serialize_object_add_string(object_list, "@id", creation->id) && + spdxtool_serialize_object_add_string(object_list, "created", creation->created))) + { + /* created_by or created_using has not been handed to the object list yet */ + spdxtool_serialize_array_free(created_by); + spdxtool_serialize_array_free(created_using); + goto err; + } + /* object_add_array takes ownership of created_by, freeing it on failure */ - if (!(spdxtool_serialize_object_add_array(object_list, "createdBy", created_by) && + if (!spdxtool_serialize_object_add_array(object_list, "createdBy", created_by)) + { + spdxtool_serialize_array_free(created_using); + goto err; + } + + /* object_add_array takes ownership of created_using, freeing it on failure */ + if (!(spdxtool_serialize_object_add_array(object_list, "createUsing", created_using) && spdxtool_serialize_object_add_string(object_list, "specVersion", creation->spec_version))) { goto err; @@ -523,10 +657,14 @@ spdxtool_core_spdx_document_add_license(pkgconf_client_t *client, spdxtool_core_ return false; } - pkgconf_node_insert_tail(node, expression, &spdx->licenses); if (!spdxtool_core_spdx_document_add_element(client, spdx, expression->spdx_id)) + { + spdxtool_simplelicensing_licenseExpression_free(expression); + free(node); return false; + } + pkgconf_node_insert_tail(node, expression, &spdx->licenses); return true; } @@ -613,11 +751,14 @@ spdxtool_core_spdx_document_add_maintainer(pkgconf_client_t *client, spdxtool_co return NULL; } - pkgconf_node_insert_tail(node, agent, &spdx->maintainers); - if (!spdxtool_core_spdx_document_add_element(client, spdx, agent->spdx_id)) + { + free(node); + spdxtool_core_agent_free(agent); return NULL; + } + pkgconf_node_insert_tail(node, agent, &spdx->maintainers); return agent->spdx_id; } @@ -710,12 +851,12 @@ spdxtool_core_relationship_new(pkgconf_client_t *client, const char *creation_in relationship->creation_info = strdup(creation_info_id); relationship->spdx_id = strdup(spdx_id); relationship->from = strdup(from); - relationship->to = to; relationship->relationship_type = strdup(relationship_type); if (!relationship->creation_info || !relationship->spdx_id || !relationship->from || !relationship->relationship_type) goto err; + relationship->to = to; return relationship; err: diff --git a/contrib/pkgconf/cli/spdxtool/core.h b/contrib/pkgconf/cli/spdxtool/core.h index 9575310ebd1f..6f55552c89d9 100644 --- a/contrib/pkgconf/cli/spdxtool/core.h +++ b/contrib/pkgconf/cli/spdxtool/core.h @@ -28,8 +28,17 @@ spdxtool_core_agent_free(spdxtool_core_agent_t *agent); spdxtool_serialize_value_t * spdxtool_core_agent_to_object(pkgconf_client_t *client, const spdxtool_core_agent_t *agent); +spdxtool_core_tool_t * +spdxtool_core_tool_new(pkgconf_client_t *client, const char *creation_info_id, const char *short_name, const char *name); + +void +spdxtool_core_tool_free(spdxtool_core_tool_t *tool); + +spdxtool_serialize_value_t * +spdxtool_core_tool_to_object(pkgconf_client_t *client, const spdxtool_core_tool_t *tool); + spdxtool_core_creation_info_t * -spdxtool_core_creation_info_new(pkgconf_client_t *client, const char *agent_id, const char *id, const char *time); +spdxtool_core_creation_info_new(pkgconf_client_t *client, const char *agent_id, const char *tool_id, const char *id, const char *time); void spdxtool_core_creation_info_free(spdxtool_core_creation_info_t *creation); diff --git a/contrib/pkgconf/cli/spdxtool/generate.c b/contrib/pkgconf/cli/spdxtool/generate.c index c5d8b29229c4..cf2d2c91bb4e 100644 --- a/contrib/pkgconf/cli/spdxtool/generate.c +++ b/contrib/pkgconf/cli/spdxtool/generate.c @@ -17,20 +17,47 @@ #include "simplelicensing.h" #include "generate.h" +typedef struct { + spdxtool_core_spdx_document_t *document; + bool failed; +} generate_spdx_ctx_t; + +static bool +generate_spdx_document_add_sbom(pkgconf_client_t *client, spdxtool_core_spdx_document_t *document, spdxtool_software_sbom_t *sbom) +{ + pkgconf_node_t *node = calloc(1, sizeof(pkgconf_node_t)); + if (!node) + { + pkgconf_error(client, "generate_spdx_document_add_sbom: out of memory"); + return false; + } + + pkgconf_node_insert_tail(node, sbom, &document->rootElement); + return true; +} + // NOTE: this function is passed to pkgconf_pkg_traverse static void -generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr) +generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr, unsigned int iter_flags) { - spdxtool_core_spdx_document_t *document = (spdxtool_core_spdx_document_t *)ptr; - pkgconf_node_t *node = NULL; + (void) iter_flags; + + generate_spdx_ctx_t *ctx = ptr; + spdxtool_core_spdx_document_t *document = ctx->document; + pkgconf_node_t *iter = NULL; spdxtool_software_sbom_t *sbom = NULL; char *package_spdx = NULL; char *spdx_id_string = NULL; + pkgconf_buffer_t spdx_id_buf = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t concluded_buf = PKGCONF_BUFFER_INITIALIZER; char sep = spdxtool_util_get_uri_separator(client); if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL) return; + if (ctx->failed) + return; + spdx_id_string = spdxtool_util_get_spdx_id_string(client, "software_Sbom", pkg->id); if (!spdx_id_string) goto err; @@ -48,12 +75,16 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr) if (!package_spdx) goto err; - pkgconf_tuple_add(client, &pkg->vars, "spdxId", package_spdx, false, 0); + if (pkgconf_tuple_add(client, &pkg->vars, "spdxId", package_spdx, false, 0) == NULL) + goto err; free(package_spdx); package_spdx = NULL; - pkgconf_tuple_add(client, &pkg->vars, "creationInfo", document->creation_info, false, 0); - pkgconf_tuple_add(client, &pkg->vars, "agent", document->agent, false, 0); + if (pkgconf_tuple_add(client, &pkg->vars, "creationInfo", document->creation_info, false, 0) == NULL || + pkgconf_tuple_add(client, &pkg->vars, "agent", document->agent, false, 0) == NULL) + { + goto err; + } if (pkg->maintainer != NULL) { @@ -61,14 +92,15 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr) if (!supplier) goto err; - pkgconf_tuple_add(client, &pkg->vars, "suppliedBy", supplier, false, 0); + if (pkgconf_tuple_add(client, &pkg->vars, "suppliedBy", supplier, false, 0) == NULL) + goto err; } if (pkg->license.head != NULL) { - pkgconf_buffer_t spdx_id_buf = PKGCONF_BUFFER_INITIALIZER; + if (!pkgconf_buffer_append_fmt(&spdx_id_buf, "%s%chasDeclaredLicense", pkg->id, sep)) + goto err; - pkgconf_buffer_append_fmt(&spdx_id_buf, "%s%chasDeclaredLicense", pkg->id, sep); char *spdx_id_name = pkgconf_buffer_freeze(&spdx_id_buf); if (!spdx_id_name) goto err; @@ -78,12 +110,14 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr) if (!package_spdx) goto err; - pkgconf_tuple_add(client, &pkg->vars, "hasDeclaredLicense", package_spdx, false, 0); + if (pkgconf_tuple_add(client, &pkg->vars, "hasDeclaredLicense", package_spdx, false, 0) == NULL) + goto err; free(package_spdx); package_spdx = NULL; - pkgconf_buffer_t concluded_buf = PKGCONF_BUFFER_INITIALIZER; - pkgconf_buffer_append_fmt(&concluded_buf, "%s%chasConcludedLicense", pkg->id, sep); + if (!pkgconf_buffer_append_fmt(&concluded_buf, "%s%chasConcludedLicense", pkg->id, sep)) + goto err; + spdx_id_name = pkgconf_buffer_freeze(&concluded_buf); if (!spdx_id_name) goto err; @@ -93,13 +127,14 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr) if (!package_spdx) goto err; - pkgconf_tuple_add(client, &pkg->vars, "hasConcludedLicense", package_spdx, false, 0); + if (pkgconf_tuple_add(client, &pkg->vars, "hasConcludedLicense", package_spdx, false, 0) == NULL) + goto err; free(package_spdx); package_spdx = NULL; - PKGCONF_FOREACH_LIST_ENTRY(pkg->license.head, node) + PKGCONF_FOREACH_LIST_ENTRY(pkg->license.head, iter) { - const pkgconf_license_t *license = node->data; + const pkgconf_license_t *license = iter->data; if (license->type == PKGCONF_LICENSE_EXPRESSION) { if (!spdxtool_core_spdx_document_add_license(client, document, license->data)) @@ -108,17 +143,19 @@ generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr) } } - node = calloc(1, sizeof(pkgconf_node_t)); - if (!node) + if (!generate_spdx_document_add_sbom(client, document, sbom)) goto err; - pkgconf_node_insert_tail(node, sbom, &document->rootElement); + sbom = NULL; return; err: + ctx->failed = true; pkgconf_error(client, "generate_spdx_package: failed for %s", pkg->id); free(package_spdx); free(spdx_id_string); + pkgconf_buffer_finalize(&spdx_id_buf); + pkgconf_buffer_finalize(&concluded_buf); spdxtool_software_sbom_free(sbom); } @@ -128,6 +165,8 @@ spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out, int { const char *agent_name_string = agent_name ? agent_name : "Default"; const char *creation_id_string = creation_id ? creation_id : "_:creationinfo_1"; + const char *tool_short_name_string = "spdxtool"; + const char *tool_name_string = "spdxtool"; spdxtool_core_agent_t *agent = spdxtool_core_agent_new(client, creation_id_string, agent_name_string); if (!agent) @@ -136,10 +175,19 @@ spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out, int return false; } - spdxtool_core_creation_info_t *creation = spdxtool_core_creation_info_new(client, agent->spdx_id, creation_id_string, creation_time); + spdxtool_core_tool_t *tool = spdxtool_core_tool_new(client, creation_id_string, tool_short_name_string, tool_name_string); + if (!tool) + { + pkgconf_error(client, "Could not create tool struct"); + spdxtool_core_agent_free(agent); + return false; + } + + spdxtool_core_creation_info_t *creation = spdxtool_core_creation_info_new(client, agent->spdx_id, tool->spdx_id, creation_id_string, creation_time); if (!creation) { pkgconf_error(client, "Could not create creation info struct"); + spdxtool_core_tool_free(tool); spdxtool_core_agent_free(agent); return false; } @@ -155,8 +203,11 @@ spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out, int return false; } - int eflag = pkgconf_pkg_traverse(client, world, generate_spdx_package, document, maxdepth, 0); - if (eflag != PKGCONF_PKG_ERRF_OK) + generate_spdx_ctx_t ctx = { + .document = document, + }; + int eflag = pkgconf_pkg_traverse(client, world, generate_spdx_package, &ctx, maxdepth, 0); + if (eflag != PKGCONF_PKG_ERRF_OK || ctx.failed) { spdxtool_core_spdx_document_free(document); spdxtool_core_creation_info_free(creation); @@ -164,7 +215,7 @@ spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out, int return false; } - spdxtool_serialize_value_t *root = spdxtool_serialize_sbom(client, agent, creation, document); + spdxtool_serialize_value_t *root = spdxtool_serialize_sbom(client, agent, tool, creation, document); if (!root) { spdxtool_core_spdx_document_free(document); @@ -174,17 +225,24 @@ spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out, int } pkgconf_buffer_t buffer = PKGCONF_BUFFER_INITIALIZER; - spdxtool_serialize_value_to_buf(&buffer, root, 0); + bool ret = spdxtool_serialize_value_to_buf(&buffer, root, 0); spdxtool_serialize_value_free(root); - bool ret = pkgconf_output_file_fmt(out, "%s\n", pkgconf_buffer_str(&buffer)); + if (ret) + { + ret = pkgconf_output_file_fmt(out, "%s\n", pkgconf_buffer_str(&buffer)); + if (!ret) + pkgconf_error(client, "spdxtool: Could not output to file: %s", strerror(errno)); + } + else + pkgconf_error(client, "spdxtool: Could not serialize SPDX document"); + pkgconf_buffer_finalize(&buffer); spdxtool_core_spdx_document_free(document); spdxtool_core_creation_info_free(creation); + spdxtool_core_tool_free(tool); spdxtool_core_agent_free(agent); - if (!ret) - pkgconf_error(client, "spdxtool: Could not output to file: %s", strerror(errno)); return ret; } diff --git a/contrib/pkgconf/cli/spdxtool/main.c b/contrib/pkgconf/cli/spdxtool/main.c index a514341b93ab..fb54d93c75de 100644 --- a/contrib/pkgconf/cli/spdxtool/main.c +++ b/contrib/pkgconf/cli/spdxtool/main.c @@ -87,8 +87,8 @@ usage(void) printf(" --creation-time Use string as creation time (Should be in ISO8601 format) [default: current time]\n"); printf(" --creation-id Use string as creation id [default: '_:creationinfo_1']\n"); printf(" --help this message\n"); - printf(" --about print bomtool version and license to stdout\n"); - printf(" --version print bomtool version to stdout\n"); + printf(" --about print spdxtool version and license to stdout\n"); + printf(" --version print spdxtool version to stdout\n"); printf(" --output FILE output SBOM data to file\n"); printf(" --spdx-base-id URL Uset string as base of SPDX ids [default: %s]\n", xsd_any_uri_default_base); printf(" --use-uri Use URIs not URLs as SPDX id"); @@ -177,7 +177,12 @@ main(int argc, char *argv[]) } } - pkgconf_client_init(&pkg_client, error_handler, NULL, personality, NULL, environ_lookup_handler); + pkgconf_client_options_t client_options = { + .error_handler = error_handler, + .personality = personality, + .environ_lookup_handler = environ_lookup_handler, + }; + pkgconf_client_init_with_options(&pkg_client, &client_options); /* we have determined what features we want most likely. in some cases, we override later. */ pkgconf_client_set_flags(&pkg_client, want_client_flags); @@ -203,10 +208,15 @@ main(int argc, char *argv[]) while (pkg_optind < argc && argv[pkg_optind] != NULL) { - if (pkgconf_buffer_len(&queryparams) > 0) - pkgconf_buffer_push_byte(&queryparams, ' '); + if ((pkgconf_buffer_len(&queryparams) > 0 && + !pkgconf_buffer_push_byte(&queryparams, ' ')) || + !pkgconf_buffer_append(&queryparams, argv[pkg_optind])) + { + pkgconf_buffer_finalize(&queryparams); + ret = EXIT_FAILURE; + goto out; + } - pkgconf_buffer_append(&queryparams, argv[pkg_optind]); pkg_optind++; } @@ -215,6 +225,13 @@ main(int argc, char *argv[]) pkgconf_buffer_finalize(&queryparams); + if (pkgq.head == NULL) + { + pkgconf_output_file_fmt(stderr, "Please specify at least one package name on the command line.\n"); + ret = EXIT_FAILURE; + goto out; + } + if (!pkgconf_queue_solve(&pkg_client, &pkgq, &world, maximum_traverse_depth)) { ret = EXIT_FAILURE; diff --git a/contrib/pkgconf/cli/spdxtool/serialize.c b/contrib/pkgconf/cli/spdxtool/serialize.c index 813095b8b7ee..8e4a5dd79a66 100644 --- a/contrib/pkgconf/cli/spdxtool/serialize.c +++ b/contrib/pkgconf/cli/spdxtool/serialize.c @@ -18,48 +18,60 @@ #include "simplelicensing.h" #include "serialize.h" -static void +static bool serialize_escape_string(pkgconf_buffer_t *buffer, const char *s) { for (const char *p = s; *p; p++) { + bool ret; + switch (*p) { case '\"': - pkgconf_buffer_append(buffer, "\\\""); + ret = pkgconf_buffer_append(buffer, "\\\""); break; case '\\': - pkgconf_buffer_append(buffer, "\\\\"); + ret = pkgconf_buffer_append(buffer, "\\\\"); break; case '\b': - pkgconf_buffer_append(buffer, "\\b"); + ret = pkgconf_buffer_append(buffer, "\\b"); break; case '\f': - pkgconf_buffer_append(buffer, "\\f"); + ret = pkgconf_buffer_append(buffer, "\\f"); break; case '\n': - pkgconf_buffer_append(buffer, "\\n"); + ret = pkgconf_buffer_append(buffer, "\\n"); break; case '\r': - pkgconf_buffer_append(buffer, "\\r"); + ret = pkgconf_buffer_append(buffer, "\\r"); break; case '\t': - pkgconf_buffer_append(buffer, "\\t"); + ret = pkgconf_buffer_append(buffer, "\\t"); break; default: if ((unsigned char) *p < 0x20) - pkgconf_buffer_append_fmt(buffer, "\\u%04x", (unsigned int)(unsigned char) *p); + ret = pkgconf_buffer_append_fmt(buffer, "\\u%04x", (unsigned int)(unsigned char) *p); else - pkgconf_buffer_push_byte(buffer, *p); + ret = pkgconf_buffer_push_byte(buffer, *p); } + + if (!ret) + return false; } + + return true; } -static inline void +static inline bool serialize_add_indent(pkgconf_buffer_t *buffer, unsigned int level) { for (; level; level--) - pkgconf_buffer_append(buffer, " "); + { + if (!pkgconf_buffer_append(buffer, " ")) + return false; + } + + return true; } /* @@ -82,62 +94,67 @@ spdxtool_serialize_value_to_buf(pkgconf_buffer_t *buffer, spdxtool_serialize_val switch(value->type) { case SPDXTOOL_SERIALIZE_TYPE_STRING: - pkgconf_buffer_push_byte(buffer, '"'); - serialize_escape_string(buffer, value->value.s ? value->value.s : ""); - pkgconf_buffer_push_byte(buffer, '"'); - break; + return pkgconf_buffer_push_byte(buffer, '"') && + serialize_escape_string(buffer, value->value.s ? value->value.s : "") && + pkgconf_buffer_push_byte(buffer, '"'); case SPDXTOOL_SERIALIZE_TYPE_INT: - pkgconf_buffer_append_fmt(buffer, "%d", value->value.i); - break; + return pkgconf_buffer_append_fmt(buffer, "%d", value->value.i); case SPDXTOOL_SERIALIZE_TYPE_BOOL: - pkgconf_buffer_append(buffer, value->value.b ? "true" : "false"); - break; + return pkgconf_buffer_append(buffer, value->value.b ? "true" : "false"); case SPDXTOOL_SERIALIZE_TYPE_NULL: - pkgconf_buffer_append(buffer, "null"); - break; + return pkgconf_buffer_append(buffer, "null"); case SPDXTOOL_SERIALIZE_TYPE_OBJECT: { pkgconf_node_t *iter; - pkgconf_buffer_push_byte(buffer, '{'); - pkgconf_buffer_push_byte(buffer, '\n'); + + if (value->value.o == NULL || + !pkgconf_buffer_push_byte(buffer, '{') || + !pkgconf_buffer_push_byte(buffer, '\n')) + return false; PKGCONF_FOREACH_LIST_ENTRY(value->value.o->entries.head, iter) { spdxtool_serialize_object_t *entry = iter->data; - serialize_add_indent(buffer, indent + 1); - pkgconf_buffer_append_fmt(buffer, "\"%s\": ", entry->key); - spdxtool_serialize_value_to_buf(buffer, entry->value, indent + 1); - if (iter->next) - pkgconf_buffer_push_byte(buffer, ','); - pkgconf_buffer_push_byte(buffer, '\n'); + + if (!serialize_add_indent(buffer, indent + 1) || + !pkgconf_buffer_push_byte(buffer, '"') || + !serialize_escape_string(buffer, entry->key ? entry->key : "") || + !pkgconf_buffer_append(buffer, "\": ") || + !spdxtool_serialize_value_to_buf(buffer, entry->value, indent + 1) || + (iter->next && !pkgconf_buffer_push_byte(buffer, ',')) || + !pkgconf_buffer_push_byte(buffer, '\n')) + return false; } - serialize_add_indent(buffer, indent); - pkgconf_buffer_push_byte(buffer, '}'); - break; + return serialize_add_indent(buffer, indent) && + pkgconf_buffer_push_byte(buffer, '}'); } case SPDXTOOL_SERIALIZE_TYPE_ARRAY: { pkgconf_node_t *iter; - pkgconf_buffer_push_byte(buffer, '['); - pkgconf_buffer_push_byte(buffer, '\n'); + + if (value->value.a == NULL || + !pkgconf_buffer_push_byte(buffer, '[') || + !pkgconf_buffer_push_byte(buffer, '\n')) + return false; PKGCONF_FOREACH_LIST_ENTRY(value->value.a->items.head, iter) { spdxtool_serialize_value_t *entry = iter->data; - serialize_add_indent(buffer, indent + 1); - spdxtool_serialize_value_to_buf(buffer, entry, indent + 1); - if (iter->next) - pkgconf_buffer_push_byte(buffer, ','); - pkgconf_buffer_push_byte(buffer, '\n'); + + if (!serialize_add_indent(buffer, indent + 1) || + !spdxtool_serialize_value_to_buf(buffer, entry, indent + 1) || + (iter->next && !pkgconf_buffer_push_byte(buffer, ',')) || + !pkgconf_buffer_push_byte(buffer, '\n')) + return false; } - serialize_add_indent(buffer, indent); - pkgconf_buffer_push_byte(buffer, ']'); - break; + + return serialize_add_indent(buffer, indent) && + pkgconf_buffer_push_byte(buffer, ']'); } } - return true; + return false; } /* @@ -375,7 +392,7 @@ spdxtool_serialize_array_free(spdxtool_serialize_array_t *array) * :return: spdxtool_serialize_value_t * representing the complete JSON-LD document, or a null string value on allocation failure. */ spdxtool_serialize_value_t * -spdxtool_serialize_sbom(pkgconf_client_t *client, spdxtool_core_agent_t *agent, spdxtool_core_creation_info_t *creation, spdxtool_core_spdx_document_t *spdx) +spdxtool_serialize_sbom(pkgconf_client_t *client, spdxtool_core_agent_t *agent, spdxtool_core_tool_t *tool, spdxtool_core_creation_info_t *creation, spdxtool_core_spdx_document_t *spdx) { const char *errstr = "out of memory"; spdxtool_serialize_value_t *ret = NULL; @@ -394,6 +411,9 @@ spdxtool_serialize_sbom(pkgconf_client_t *client, spdxtool_core_agent_t *agent, if (!spdxtool_serialize_array_add_take(graph, spdxtool_core_agent_to_object(client, agent))) goto err; + if (!spdxtool_serialize_array_add_take(graph, spdxtool_core_tool_to_object(client, tool))) + goto err; + if (!spdxtool_serialize_array_add_take(graph, spdxtool_core_creation_info_to_object(client, creation))) goto err; diff --git a/contrib/pkgconf/cli/spdxtool/serialize.h b/contrib/pkgconf/cli/spdxtool/serialize.h index a1eb99403406..527bfb5b6812 100644 --- a/contrib/pkgconf/cli/spdxtool/serialize.h +++ b/contrib/pkgconf/cli/spdxtool/serialize.h @@ -536,7 +536,7 @@ spdxtool_serialize_array_add_array(spdxtool_serialize_array_t *array, spdxtool_s } spdxtool_serialize_value_t * -spdxtool_serialize_sbom(pkgconf_client_t *client, spdxtool_core_agent_t *agent, spdxtool_core_creation_info_t *creation, spdxtool_core_spdx_document_t *spdx); +spdxtool_serialize_sbom(pkgconf_client_t *client, spdxtool_core_agent_t *agent, spdxtool_core_tool_t *tool, spdxtool_core_creation_info_t *creation, spdxtool_core_spdx_document_t *spdx); #ifdef __cplusplus } diff --git a/contrib/pkgconf/cli/spdxtool/software.c b/contrib/pkgconf/cli/spdxtool/software.c index c95ec84cbdfa..d9b753b78f53 100644 --- a/contrib/pkgconf/cli/spdxtool/software.c +++ b/contrib/pkgconf/cli/spdxtool/software.c @@ -16,6 +16,25 @@ #include "software.h" #include "core.h" +static char * +relationship_spdx_id(pkgconf_client_t *client, const char *from, const char *to, char sep) +{ + pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER; + char *spdx_id = NULL; + + if (!pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", from, sep, sep, to)) + goto out; + + if (pkgconf_buffer_len(&relationship_buf) == 0) + goto out; + + spdx_id = spdxtool_util_get_spdx_id_string(client, "Relationship", pkgconf_buffer_str(&relationship_buf)); + +out: + pkgconf_buffer_finalize(&relationship_buf); + return spdx_id; +} + /* * !doc * @@ -26,7 +45,7 @@ * :param pkgconf_client_t *client: The pkgconf client being accessed. * :param const char *spdx_id: spdxId for this SBOM element * :param const char *creation_id: id for CreationInfo - * :param const char *sbom_type: Sbom types can be found SPDX documention + * :param const char *sbom_type: Sbom types can be found SPDX documentation * :return: NULL if some problem occurs and Sbom struct if not */ spdxtool_software_sbom_t * @@ -135,19 +154,12 @@ spdxtool_software_sbom_to_object(pkgconf_client_t *client, spdxtool_software_sbo { pkgconf_dependency_t *dep = node->data; pkgconf_pkg_t *match = dep->match; - pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER; /* an unresolved (but tolerated) dependency has no match */ if (match == NULL) continue; - pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", sbom->rootElement->id, sep, sep, match->id); - char *relationship_str = pkgconf_buffer_freeze(&relationship_buf); - if (!relationship_str) - goto err; - - char *spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Relationship", relationship_str); - free(relationship_str); + char *spdx_id_relation = relationship_spdx_id(client, sbom->rootElement->id, match->id, sep); if (!spdx_id_relation) goto err; @@ -170,19 +182,12 @@ spdxtool_software_sbom_to_object(pkgconf_client_t *client, spdxtool_software_sbo { pkgconf_dependency_t *dep = node->data; pkgconf_pkg_t *match = dep->match; - pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER; /* an unresolved (but tolerated) dependency has no match */ if (match == NULL) continue; - pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", sbom->rootElement->id, sep, sep, match->id); - char *relationship_str = pkgconf_buffer_freeze(&relationship_buf); - if (!relationship_str) - goto err; - - char *spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Relationship", relationship_str); - free(relationship_str); + char *spdx_id_relation = relationship_spdx_id(client, sbom->rootElement->id, match->id, sep); if (!spdx_id_relation) goto err; @@ -293,7 +298,11 @@ serialize_copyright_lines_to_object(spdxtool_serialize_object_list_t *object_lis PKGCONF_FOREACH_LIST_ENTRY(copyright_lines->head, node) { const pkgconf_bufferset_t *set = node->data; - pkgconf_buffer_join(©right_buf, '\n', pkgconf_buffer_str_or_empty(&set->buffer), NULL); + if (!pkgconf_buffer_join(©right_buf, '\n', pkgconf_buffer_str_or_empty(&set->buffer), NULL)) + { + pkgconf_buffer_finalize(©right_buf); + return false; + } } bool ok = spdxtool_serialize_object_add_string(object_list, "software_copyrightText", pkgconf_buffer_str_or_empty(©right_buf)) != NULL; @@ -321,7 +330,6 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg spdxtool_serialize_value_t *ret = NULL; spdxtool_serialize_object_list_t *object_list = NULL; spdxtool_serialize_array_t *originated_by = NULL; - spdxtool_serialize_array_t *supplied_by = NULL; char *creation_info = NULL; char *spdx_id = NULL; char *agent = NULL; @@ -368,20 +376,8 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg goto err; supplier = spdxtool_util_tuple_lookup(client, &pkg->vars, "suppliedBy"); - if (supplier) - { - supplied_by = spdxtool_serialize_array_new(); - if (!supplied_by) - goto err; - - if (!spdxtool_serialize_array_add_string(supplied_by, supplier)) - goto err; - - ok = spdxtool_serialize_object_add_array(object_list, "suppliedBy", supplied_by); - supplied_by = NULL; - if (!ok) - goto err; - } + if (supplier && !spdxtool_serialize_object_add_string(object_list, "suppliedBy", supplier)) + goto err; if (!serialize_copyright_lines_to_object(object_list, &pkg->copyright)) goto err; @@ -410,7 +406,8 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg if (!spdx_id_license) goto err; - pkgconf_license_insert(client, &relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_license); + if (!pkgconf_license_insert(client, &relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_license)) + goto err; free(spdx_id_license); spdx_id_license = NULL; } @@ -426,14 +423,21 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg goto err; } - pkgconf_license_copy_list(client, cpy_relations, &relations); + if (!pkgconf_license_copy_list(client, cpy_relations, &relations)) + { + free(tuple_license); + goto err; + } spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, tuple_license, spdx_id, cpy_relations, "hasDeclaredLicense"); free(tuple_license); if (!relationship) goto err; - if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship)) - goto err; cpy_relations = NULL; + if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship)) + { + spdxtool_core_relationship_free(relationship); + goto err; + } } tuple_license = spdxtool_util_tuple_lookup(client, &pkg->vars, "hasConcludedLicense"); @@ -446,14 +450,21 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg goto err; } - pkgconf_license_copy_list(client, cpy_relations, &relations); + if (!pkgconf_license_copy_list(client, cpy_relations, &relations)) + { + free(tuple_license); + goto err; + } spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, tuple_license, spdx_id, cpy_relations, "hasConcludedLicense"); free(tuple_license); if (!relationship) goto err; - if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship)) - goto err; cpy_relations = NULL; + if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship)) + { + spdxtool_core_relationship_free(relationship); + goto err; + } } pkgconf_license_free(&relations); @@ -461,19 +472,12 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg { pkgconf_dependency_t *dep = node->data; pkgconf_pkg_t *match = dep->match; - pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER; /* an unresolved (but tolerated) dependency has no match */ if (match == NULL) continue; - pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", pkg->id, sep, sep, match->id); - char *relationship_str = pkgconf_buffer_freeze(&relationship_buf); - if (!relationship_str) - goto err; - - char *spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Relationship", relationship_str); - free(relationship_str); + char *spdx_id_relation = relationship_spdx_id(client, pkg->id, match->id, sep); if (!spdx_id_relation) goto err; @@ -492,34 +496,35 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg goto err; } - pkgconf_license_insert(client, cpy_relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_package); + if (!pkgconf_license_insert(client, cpy_relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_package)) + { + free(spdx_id_relation); + free(spdx_id_package); + goto err; + } spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, spdx_id_relation, spdx_id, cpy_relations, "dependsOn"); free(spdx_id_relation); free(spdx_id_package); if (!relationship) goto err; - if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship)) - goto err; cpy_relations = NULL; + if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship)) + { + spdxtool_core_relationship_free(relationship); + goto err; + } } PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_private.head, node) { pkgconf_dependency_t *dep = node->data; pkgconf_pkg_t *match = dep->match; - pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER; /* an unresolved (but tolerated) dependency has no match */ if (match == NULL) continue; - pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", pkg->id, sep, sep, match->id); - char *relationship_str = pkgconf_buffer_freeze(&relationship_buf); - if (!relationship_str) - goto err; - - char *spdx_id_relation = spdxtool_util_get_spdx_id_string(client, "Relationship", relationship_str); - free(relationship_str); + char *spdx_id_relation = relationship_spdx_id(client, pkg->id, match->id, sep); if (!spdx_id_relation) goto err; @@ -538,7 +543,12 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg goto err; } - pkgconf_license_insert(client, cpy_relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_package); + if (!pkgconf_license_insert(client, cpy_relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_package)) + { + free(spdx_id_relation); + free(spdx_id_package); + goto err; + } spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, spdx_id_relation, spdx_id, cpy_relations, "dependsOn"); free(spdx_id_relation); free(spdx_id_package); @@ -569,8 +579,13 @@ err: free(agent); free(supplier); free(spdx_id_license); + pkgconf_license_free(&relations); + if (cpy_relations != NULL) + { + pkgconf_license_free(cpy_relations); + free(cpy_relations); + } spdxtool_serialize_object_list_free(object_list); spdxtool_serialize_array_free(originated_by); - spdxtool_serialize_array_free(supplied_by); return ret; } diff --git a/contrib/pkgconf/cli/spdxtool/util.c b/contrib/pkgconf/cli/spdxtool/util.c index fa717aaa6102..722acb394f73 100644 --- a/contrib/pkgconf/cli/spdxtool/util.c +++ b/contrib/pkgconf/cli/spdxtool/util.c @@ -16,12 +16,82 @@ #include #include "util.h" +static bool +util_escape_uri_string(pkgconf_buffer_t *dest, pkgconf_buffer_t *src) +{ + const char *p = pkgconf_buffer_str(src); + + if (dest == src) + return false; + + if (!p) + return true; + + for (; *p; p++) + { + bool ret; + + switch (*p) + { + case 0x20: + ret = pkgconf_buffer_append(dest, "%20"); + break; + case '"': + ret = pkgconf_buffer_append(dest, "%22"); + break; + case '%': + ret = pkgconf_buffer_append(dest, "%25"); + break; + case '\'': + ret = pkgconf_buffer_append(dest, "%27"); + break; + case '+': + ret = pkgconf_buffer_append(dest, "%2B"); + break; + case ',': + ret = pkgconf_buffer_append(dest, "%2C"); + break; + case '<': + ret = pkgconf_buffer_append(dest, "%3C"); + break; + case '>': + ret = pkgconf_buffer_append(dest, "%3E"); + break; + case '\\': + ret = pkgconf_buffer_append(dest, "%5C"); + break; + case '^': + ret = pkgconf_buffer_append(dest, "%5E"); + break; + case '`': + ret = pkgconf_buffer_append(dest, "%60"); + break; + case '{': + ret = pkgconf_buffer_append(dest, "%7B"); + break; + case '|': + ret = pkgconf_buffer_append(dest, "%7C"); + break; + case '}': + ret = pkgconf_buffer_append(dest, "%7D"); + break; + default: + ret = pkgconf_buffer_push_byte(dest, *p); + } + + if (!ret) + return false; + } + + return true; +} + /* * !doc * * .. c:function:: void spdxtool_util_set_key(pkgconf_client_t *client, const char *key, const char *key_value, const char *key_default) * - * Set key wit default value. Default value is used if key is NULL + * Set key with default value. Default value is used if key is NULL * * :param pkgconf_client_t* client: The pkgconf client being accessed. * :param const char *key: Key to be preserved @@ -179,11 +249,28 @@ spdxtool_util_get_spdx_id_int(pkgconf_client_t *client, const char *part) const char *global_xsd_any_uri = spdxtool_util_get_uri_root(client); char sep = spdxtool_util_get_uri_separator(client); pkgconf_buffer_t current_uri = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t escaped_uri = PKGCONF_BUFFER_INITIALIZER; - pkgconf_buffer_join(¤t_uri, sep, global_xsd_any_uri, part, NULL); - pkgconf_buffer_append_fmt(¤t_uri, "%c" SIZE_FMT_SPECIFIER, sep, ++last_id); + if (last_id == SIZE_MAX || + !pkgconf_buffer_join(¤t_uri, sep, global_xsd_any_uri, part, NULL) || + !pkgconf_buffer_append_fmt(¤t_uri, "%c" SIZE_FMT_SPECIFIER, sep, last_id + 1)) + { + pkgconf_buffer_finalize(¤t_uri); + return NULL; + } - return pkgconf_buffer_freeze(¤t_uri); + last_id++; + + if (!util_escape_uri_string(&escaped_uri, ¤t_uri)) + { + pkgconf_buffer_finalize(¤t_uri); + pkgconf_buffer_finalize(&escaped_uri); + return NULL; + } + + pkgconf_buffer_finalize(¤t_uri); + + return pkgconf_buffer_freeze(&escaped_uri); } /* @@ -205,10 +292,24 @@ spdxtool_util_get_spdx_id_string(pkgconf_client_t *client, const char *part, con const char *global_xsd_any_uri = spdxtool_util_get_uri_root(client); char sep = spdxtool_util_get_uri_separator(client); pkgconf_buffer_t current_uri = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t escaped_uri = PKGCONF_BUFFER_INITIALIZER; - pkgconf_buffer_join(¤t_uri, sep, global_xsd_any_uri, part, string_id, NULL); + if (!pkgconf_buffer_join(¤t_uri, sep, global_xsd_any_uri, part, string_id, NULL)) + { + pkgconf_buffer_finalize(¤t_uri); + return NULL; + } - return pkgconf_buffer_freeze(¤t_uri); + if (!util_escape_uri_string(&escaped_uri, ¤t_uri)) + { + pkgconf_buffer_finalize(¤t_uri); + pkgconf_buffer_finalize(&escaped_uri); + return NULL; + } + + pkgconf_buffer_finalize(¤t_uri); + + return pkgconf_buffer_freeze(&escaped_uri); } /* @@ -314,7 +415,10 @@ spdxtool_util_tuple_lookup(pkgconf_client_t *client, pkgconf_list_t *vars, const return NULL; if (!pkgconf_variable_eval(client, vars, v, &buf, NULL)) + { + pkgconf_buffer_finalize(&buf); return NULL; + } return pkgconf_buffer_freeze(&buf); } diff --git a/contrib/pkgconf/cli/spdxtool/util.h b/contrib/pkgconf/cli/spdxtool/util.h index 645d93a5a8e9..0bcd365f26bd 100644 --- a/contrib/pkgconf/cli/spdxtool/util.h +++ b/contrib/pkgconf/cli/spdxtool/util.h @@ -28,13 +28,22 @@ typedef struct spdxtool_core_agent_ char *name; } spdxtool_core_agent_t; +typedef struct spdxtool_core_tool_ +{ + char *spdx_id; + const char *type; + char *creation_info; + char *name; +} spdxtool_core_tool_t; + typedef struct spdxtool_core_creation_info_ { char *id; const char *type; char *created; char *created_by; - const char *created_using; + char *create_using; + char *created_using; char *spec_version; } spdxtool_core_creation_info_t; diff --git a/contrib/pkgconf/configure.ac b/contrib/pkgconf/configure.ac index ec5906a564ce..78d2b9588135 100644 --- a/contrib/pkgconf/configure.ac +++ b/contrib/pkgconf/configure.ac @@ -12,7 +12,7 @@ dnl implied. In no event shall the authors be liable for any damages arising dnl from the use of this software. AC_PREREQ([2.71]) -AC_INIT([pkgconf],[2.9.93],[https://github.com/pkgconf/pkgconf/issues/new]) +AC_INIT([pkgconf],[3.0.9],[https://github.com/pkgconf/pkgconf/issues/new]) AC_MSG_WARN([ =================================================================== Autotools support is deprecated and will be removed in pkgconf 3.1. @@ -25,12 +25,14 @@ AX_CHECK_COMPILE_FLAG([-Wall], [CFLAGS="$CFLAGS -Wall"]) AX_CHECK_COMPILE_FLAG([-Wextra], [CFLAGS="$CFLAGS -Wextra"]) AX_CHECK_COMPILE_FLAG([-Wformat=2], [CFLAGS="$CFLAGS -Wformat=2"]) AX_CHECK_COMPILE_FLAG([-std=c99], [CFLAGS="$CFLAGS -std=c99"]) -CPPFLAGS="$CPPFLAGS -D_BSD_SOURCE -D_DARWIN_C_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700" +CPPFLAGS="$CPPFLAGS -D_ATFILE_SOURCE -D_BSD_SOURCE -D_DARWIN_C_SOURCE -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700" AC_CONFIG_HEADERS([libpkgconf/config.h]) AC_CHECK_DECLS([strndup], [], [], [[#include ]]) AC_CHECK_DECLS([pledge, unveil], [], [], [[#include ]]) AC_CHECK_DECLS([readlinkat], [], [], [[#include ]]) AC_CHECK_DECLS([reallocarray], [], [], [[#include ]]) +AC_CHECK_DECLS([mkdtemp], [], [], [[#include ]]) +AC_CHECK_DECLS([getc_unlocked], [], [], [[#include ]]) AC_CHECK_DECLS([nl_langinfo_l], [], [], [[ #ifdef __APPLE__ #include diff --git a/contrib/pkgconf/fuzzer/spdxtool-fuzzer.c b/contrib/pkgconf/fuzzer/spdxtool-fuzzer.c index 3db2fb0fd5c8..ce4279725058 100644 --- a/contrib/pkgconf/fuzzer/spdxtool-fuzzer.c +++ b/contrib/pkgconf/fuzzer/spdxtool-fuzzer.c @@ -25,7 +25,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); -/* bound the number of injection rounds per input to keep executions cheap */ +/* Bound the allocation site selected for fault injection. Exhaustively + * replaying every allocation for every libFuzzer input makes this relatively + * expensive solve-and-serialize target prohibitively slow. */ #define ALLOC_FAIL_MAX 4096 /* the fuzzer input is split on NUL bytes into up to this many .pc files, named @@ -37,6 +39,20 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); static const char universe_names[UNIVERSE_MAX] = { 'a', 'b', 'c', 'd' }; +static unsigned long +allocation_failure_for_input(const uint8_t *data, size_t size) +{ + uint32_t hash = UINT32_C(2166136261); + + for (size_t i = 0; i < size; i++) + { + hash ^= data[i]; + hash *= UINT32_C(16777619); + } + + return (unsigned long)(hash % ALLOC_FAIL_MAX) + 1; +} + static const char * environ_lookup_handler(const pkgconf_client_t *client, const char *key) { @@ -181,16 +197,11 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) /* baseline run with all allocations succeeding */ run_spdx(pers, dir, out); - /* then fail each allocation site reachable by this input, one at a time */ - for (unsigned long i = 1; i <= ALLOC_FAIL_MAX; i++) - { - alloc_inject_arm(i); - run_spdx(pers, dir, out); - alloc_inject_disarm(); - - if (!alloc_inject_fired()) - break; - } + /* Exercise one deterministic allocation failure per input. Mutations vary + * the selected site, while keeping the per-input cost constant. */ + alloc_inject_arm(allocation_failure_for_input(data, size)); + run_spdx(pers, dir, out); + alloc_inject_disarm(); pkgconf_cross_personality_deinit(pers); fclose(out); diff --git a/contrib/pkgconf/libpkgconf.pc.in b/contrib/pkgconf/libpkgconf.pc.in index ca02a375524e..11f823e38efb 100644 --- a/contrib/pkgconf/libpkgconf.pc.in +++ b/contrib/pkgconf/libpkgconf.pc.in @@ -8,6 +8,7 @@ datadir=@datadir@ Name: libpkgconf Description: a library for accessing and manipulating development framework configuration URL: https://github.com/pkgconf/pkgconf +Maintainer: Ariadne Conill License: ISC License.file: ${datadir}/doc/pkgconf/COPYING Source: https://github.com/pkgconf/pkgconf diff --git a/contrib/pkgconf/libpkgconf/argvsplit.c b/contrib/pkgconf/libpkgconf/argvsplit.c index 8c5dac2917df..b8bb0fa7cbf2 100644 --- a/contrib/pkgconf/libpkgconf/argvsplit.c +++ b/contrib/pkgconf/libpkgconf/argvsplit.c @@ -49,20 +49,15 @@ pkgconf_argv_free(char **argv) } /* - * !doc + * Walk `src`, breaking it at whitespace which is neither quoted nor escaped. * - * .. c:function:: int pkgconf_argv_split(const char *src, int *argc, char ***argv) - * - * Splits a string into an argument vector. - * - * :param char* src: The string to split. - * :param int* argc: A pointer to an integer to store the argument count. - * :param char*** argv: A pointer to a pointer for an argument vector. - * :return: 0 on success, -1 on error. - * :rtype: int + * When `raw` is set, the quoting and escaping is only read to find those breaks: + * the quotes and backslashes are copied into the argument along with everything + * else, leaving it spelled exactly as it was written. Otherwise they are + * consumed, as a shell would consume them. */ -int -pkgconf_argv_split(const char *src, int *argc, char ***argv) +static int +argv_split(const char *src, int *argc, char ***argv, bool raw) { char *buf = calloc(1, strlen(src) + 1); if (buf == NULL) @@ -92,7 +87,7 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv) if (escaped) { /* POSIX: only \CHAR is special inside a double quote if CHAR is {$, `, ", \, newline}. */ - if (quote == '"') + if (quote == '"' && !raw) { if (!(*src_iter == '$' || *src_iter == '`' || *src_iter == '"' || *src_iter == '\\')) *dst_iter++ = '\\'; @@ -109,9 +104,19 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv) else if (quote) { if (*src_iter == quote) + { quote = 0; + + if (raw) + *dst_iter++ = *src_iter; + } else if (*src_iter == '\\' && quote != '\'') + { escaped = true; + + if (raw) + *dst_iter++ = *src_iter; + } else *dst_iter++ = *src_iter; } @@ -145,11 +150,17 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv) { case '\\': escaped = true; + + if (raw) + *dst_iter++ = *src_iter; break; case '\"': case '\'': quote = *src_iter; + + if (raw) + *dst_iter++ = *src_iter; break; default: @@ -176,3 +187,48 @@ pkgconf_argv_split(const char *src, int *argc, char ***argv) *argc = argc_count; return 0; } + +/* + * !doc + * + * .. c:function:: int pkgconf_argv_split(const char *src, int *argc, char ***argv) + * + * Splits a string into an argument vector, consuming shell quoting and + * backslash escapes the way a shell would. + * + * :param char* src: The string to split. + * :param int* argc: A pointer to an integer to store the argument count. + * :param char*** argv: A pointer to a pointer for an argument vector. + * :return: 0 on success, -1 on error. + * :rtype: int + */ +int +pkgconf_argv_split(const char *src, int *argc, char ***argv) +{ + return argv_split(src, argc, argv, false); +} + +/* + * !doc + * + * .. c:function:: int pkgconf_argv_split_raw(const char *src, int *argc, char ***argv) + * + * Splits a string into an argument vector without interpreting it: the + * quoting and escaping says where the arguments end, but is left in the text. + * + * This is for input which still has to be expanded. Consuming the quoting + * here would consume only what the input itself spells, leaving whatever a + * variable substitutes into it unconsumed, so it is left for a second pass + * over the finished text. + * + * :param char* src: The string to split. + * :param int* argc: A pointer to an integer to store the argument count. + * :param char*** argv: A pointer to a pointer for an argument vector. + * :return: 0 on success, -1 on error. + * :rtype: int + */ +int +pkgconf_argv_split_raw(const char *src, int *argc, char ***argv) +{ + return argv_split(src, argc, argv, true); +} diff --git a/contrib/pkgconf/libpkgconf/bsdstubs.c b/contrib/pkgconf/libpkgconf/bsdstubs.c index 7ef3556364c0..aebf8311fbe9 100644 --- a/contrib/pkgconf/libpkgconf/bsdstubs.c +++ b/contrib/pkgconf/libpkgconf/bsdstubs.c @@ -21,7 +21,7 @@ #else /* * Creates a memory buffer and copies at most 'len' characters to it. - * If 'len' is less than the length of the source string, truncation occured. + * If 'len' is less than the length of the source string, truncation occurred. */ static inline char * pkgconf_strndup_impl(const char *src, size_t len) diff --git a/contrib/pkgconf/libpkgconf/buffer.c b/contrib/pkgconf/libpkgconf/buffer.c index 3c68caffe8ea..49fb529430c5 100644 --- a/contrib/pkgconf/libpkgconf/buffer.c +++ b/contrib/pkgconf/libpkgconf/buffer.c @@ -28,10 +28,69 @@ * dynamically-allocated buffers. */ -static inline size_t -target_allocation_size(size_t target_size) +/* buffers below BUFFER_LINEAR_GROWTH_MAX increment by 128 bytes each time */ +#define BUFFER_LINEAR_GROWTH_MAX 4096 + +static inline bool +target_allocation_size(size_t target_size, size_t *allocation_size) { - return 128 + (128 * (target_size / 128)); + if (target_size < BUFFER_LINEAR_GROWTH_MAX) + { + *allocation_size = target_size + (128 - (target_size % 128)); + return true; + } + + size_t cap = BUFFER_LINEAR_GROWTH_MAX; + while (cap <= target_size) + { + if (cap > SIZE_MAX / 2) + return false; + + cap *= 2; + } + + *allocation_size = cap; + return true; +} + +static inline bool +buffer_reserve(pkgconf_buffer_t *buffer, size_t content_len) +{ + size_t new_cap, old_cap; + char *newbase; + + if (!target_allocation_size(content_len, &new_cap)) + return false; + + if (buffer->base != NULL && target_allocation_size(pkgconf_buffer_len(buffer), &old_cap) && old_cap == new_cap) + return true; + + newbase = realloc(buffer->base, new_cap); + if (newbase == NULL) + return false; + + buffer->base = newbase; + return true; +} + +static bool +buffer_storage_overlaps(const pkgconf_buffer_t *buffer, const void *source, size_t source_size) +{ + if (buffer->base == NULL || source == NULL || source_size == 0) + return false; + + size_t buffer_size = pkgconf_buffer_len(buffer) + 1; + uintptr_t buffer_start = (uintptr_t) buffer->base; + uintptr_t source_start = (uintptr_t) source; + + if (buffer_start > UINTPTR_MAX - (buffer_size - 1) || + source_start > UINTPTR_MAX - (source_size - 1)) + return true; + + uintptr_t buffer_end = buffer_start + buffer_size - 1; + uintptr_t source_end = source_start + source_size - 1; + + return buffer_start <= source_end && source_start <= buffer_end; } #if 0 @@ -53,6 +112,7 @@ buffer_debug(pkgconf_buffer_t *buffer) * .. c:function:: bool pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text) * * Append a null-terminated string to the buffer, reallocating as necessary. + * The storage occupied by *text* must not overlap the buffer. * * :param pkgconf_buffer_t *buffer: The buffer to append to. * :param char *text: The null-terminated string to append. @@ -61,20 +121,27 @@ buffer_debug(pkgconf_buffer_t *buffer) bool pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text) { - size_t needed = strlen(text) + 1; - size_t newsize = pkgconf_buffer_len(buffer) + needed; + size_t len = pkgconf_buffer_len(buffer); + size_t text_len = strlen(text); - char *newbase = realloc(buffer->base, target_allocation_size(newsize)); - if (newbase == NULL) + if (text_len == SIZE_MAX) return false; - char *newend = newbase + pkgconf_buffer_len(buffer); - memcpy(newend, text, needed); + if (buffer_storage_overlaps(buffer, text, text_len + 1)) + return false; - buffer->base = newbase; - buffer->end = newend + (needed - 1); + if (len > SIZE_MAX - text_len) + return false; + size_t new_len = len + text_len; + if (!buffer_reserve(buffer, new_len)) + return false; + + memcpy(buffer->base + len, text, text_len); + + buffer->end = buffer->base + new_len; *buffer->end = '\0'; + return true; } @@ -84,6 +151,7 @@ pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text) * .. c:function:: bool pkgconf_buffer_append_slice(pkgconf_buffer_t *buf, const char *p, size_t n) * * Append a slice of *n* bytes to the buffer. Does nothing if *n* is zero. + * The source slice must not overlap the buffer. * * :param pkgconf_buffer_t *buf: The buffer to append to. * :param char *p: Pointer to the byte sequence to append. @@ -93,14 +161,25 @@ pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text) bool pkgconf_buffer_append_slice(pkgconf_buffer_t *buf, const char *p, size_t n) { + size_t len = pkgconf_buffer_len(buf); + if (n == 0) return true; - for (size_t i = 0; i < n; i++) - { - if (!pkgconf_buffer_push_byte(buf, p[i])) - return false; - } + if (buffer_storage_overlaps(buf, p, n)) + return false; + + if (len > SIZE_MAX - n) + return false; + + size_t new_len = len + n; + if (!buffer_reserve(buf, new_len)) + return false; + + memcpy(buf->base + len, p, n); + + buf->end = buf->base + new_len; + *buf->end = '\0'; return true; } @@ -120,27 +199,32 @@ pkgconf_buffer_append_slice(pkgconf_buffer_t *buf, const char *p, size_t n) bool pkgconf_buffer_append_vfmt(pkgconf_buffer_t *buffer, const char *fmt, va_list src_va) { + char stackbuf[256]; va_list va; - char *buf; - size_t needed; + int formatted_len; va_copy(va, src_va); - needed = vsnprintf(NULL, 0, fmt, va) + 1; + formatted_len = vsnprintf(stackbuf, sizeof stackbuf, fmt, va); va_end(va); - buf = malloc(needed); - if (buf == NULL) + if (formatted_len < 0) + return false; + + if ((size_t) formatted_len < sizeof stackbuf) + return pkgconf_buffer_append_slice(buffer, stackbuf, (size_t) formatted_len); + + size_t len = pkgconf_buffer_len(buffer); + + if (!buffer_reserve(buffer, len + (size_t) formatted_len)) return false; va_copy(va, src_va); - vsnprintf(buf, needed, fmt, va); + vsnprintf(buffer->base + len, (size_t) formatted_len + 1, fmt, va); va_end(va); - bool ret = pkgconf_buffer_append(buffer, buf); + buffer->end = buffer->base + len + (size_t) formatted_len; - free(buf); - - return ret; + return true; } /* @@ -173,6 +257,7 @@ pkgconf_buffer_append_fmt(pkgconf_buffer_t *buffer, const char *fmt, ...) * * Prepend a null-terminated string to the beginning of the buffer. * If *text* is NULL, the buffer contents are unchanged. + * The storage occupied by *text* must not overlap the buffer. * * :param pkgconf_buffer_t *buffer: The buffer to prepend to. * :param char *text: The null-terminated string to prepend, or NULL. @@ -182,6 +267,16 @@ bool pkgconf_buffer_prepend(pkgconf_buffer_t *buffer, const char *text) { pkgconf_buffer_t tmpbuf = PKGCONF_BUFFER_INITIALIZER; + bool ret = true; + + if (text != NULL) + { + size_t text_len = strlen(text); + + if (text_len == SIZE_MAX || + buffer_storage_overlaps(buffer, text, text_len + 1)) + return false; + } if (text != NULL && !pkgconf_buffer_append(&tmpbuf, text)) return false; @@ -193,11 +288,11 @@ pkgconf_buffer_prepend(pkgconf_buffer_t *buffer, const char *text) } if (pkgconf_buffer_len(&tmpbuf)) - pkgconf_buffer_copy(&tmpbuf, buffer); + ret = pkgconf_buffer_copy(&tmpbuf, buffer); pkgconf_buffer_finalize(&tmpbuf); - return true; + return ret; } /* @@ -214,17 +309,19 @@ pkgconf_buffer_prepend(pkgconf_buffer_t *buffer, const char *text) bool pkgconf_buffer_push_byte(pkgconf_buffer_t *buffer, char byte) { - size_t newsize = pkgconf_buffer_len(buffer) + 1; - char *newbase = realloc(buffer->base, target_allocation_size(newsize)); - if (newbase == NULL) + size_t len = pkgconf_buffer_len(buffer); + + if (len == SIZE_MAX) return false; - char *newend = newbase + newsize; - *(newend - 1) = byte; - *newend = '\0'; + size_t new_len = len + 1; + if (!buffer_reserve(buffer, new_len)) + return false; - buffer->base = newbase; - buffer->end = newend; + buffer->base[len] = byte; + + buffer->end = buffer->base + new_len; + *buffer->end = '\0'; return true; } @@ -246,14 +343,11 @@ pkgconf_buffer_trim_byte(pkgconf_buffer_t *buffer) if (len == 0) return false; - size_t newsize = len - 1; - char *newbase = realloc(buffer->base, target_allocation_size(newsize)); - - if (newbase == NULL) + size_t new_len = len - 1; + if (!buffer_reserve(buffer, new_len)) return false; - buffer->base = newbase; - buffer->end = newbase + newsize; + buffer->end = buffer->base + new_len; *(buffer->end) = '\0'; return true; @@ -461,6 +555,7 @@ pkgconf_buffer_match(const pkgconf_buffer_t *haystack, const pkgconf_buffer_t *n * * Copy *src* into *dest*, replacing all occurrences of *pattern* with *value*. * If *pattern* is empty, *src* is appended to *dest* unmodified. + * Neither *src*, *pattern* nor *value* may overlap *dest*. * * :param pkgconf_buffer_t *dest: The destination buffer. * :param pkgconf_buffer_t *src: The source buffer. @@ -473,6 +568,10 @@ pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const { const char *iter = src->base; + if (dest == src || + buffer_storage_overlaps(dest, src->base, pkgconf_buffer_len(src) + 1)) + return false; + if (pattern == NULL) pattern = ""; @@ -480,6 +579,9 @@ pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const value = ""; size_t pattern_len = strlen(pattern); + if (buffer_storage_overlaps(dest, pattern, pattern_len + 1) || + buffer_storage_overlaps(dest, value, strlen(value) + 1)) + return false; if (!pkgconf_buffer_len(src)) return true; @@ -513,6 +615,7 @@ pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const * * Copy *src* into *dest*, inserting a backslash before any byte that falls * within the provided character spans. + * The source and destination buffers must not overlap. * * :param pkgconf_buffer_t *dest: The destination buffer. * :param pkgconf_buffer_t *src: The source buffer. @@ -522,23 +625,104 @@ pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const */ bool pkgconf_buffer_escape(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_span_t *spans, size_t nspans) +{ + pkgconf_charset_t charset; + + pkgconf_charset_from_spans(&charset, spans, nspans); + + return pkgconf_buffer_escape_charset(dest, src, &charset); +} + +/* + * !doc + * + * .. c:function:: void pkgconf_charset_from_spans(pkgconf_charset_t *charset, const pkgconf_span_t *spans, size_t nspans) + * + * Build a byte-set from a list of character spans, so that membership tests over it are a + * single lookup. Callers which test many bytes against the same spans should build the set + * once and pass it to :c:func:`pkgconf_buffer_escape_charset`. + * + * :param pkgconf_charset_t *charset: The byte-set to populate. + * :param pkgconf_span_t *spans: Array of character spans to include. + * :param size_t nspans: Number of entries in the *spans* array. + * :return: nothing + */ +void +pkgconf_charset_from_spans(pkgconf_charset_t *charset, const pkgconf_span_t *spans, size_t nspans) +{ + memset(charset, 0, sizeof(*charset)); + + for (size_t i = 0; i < nspans; i++) + { + unsigned int lo = spans[i].lo, hi = spans[i].hi; + + if (lo > hi) + continue; + + size_t wlo = lo >> 6, whi = hi >> 6; + + /* bits at or above lo, and bits at or below hi, within their words */ + uint64_t mlo = ~UINT64_C(0) << (lo & 63); + uint64_t mhi = (hi & 63) == 63 ? ~UINT64_C(0) : (UINT64_C(1) << ((hi & 63) + 1)) - 1; + + if (wlo == whi) + { + charset->words[wlo] |= mlo & mhi; + continue; + } + + charset->words[wlo] |= mlo; + + for (size_t w = wlo + 1; w < whi; w++) + charset->words[w] = ~UINT64_C(0); + + charset->words[whi] |= mhi; + } +} + +/* + * !doc + * + * .. c:function:: bool pkgconf_buffer_escape_charset(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_charset_t *charset) + * + * Copy *src* into *dest*, inserting a backslash before any byte which is a member of + * *charset*. Like :c:func:`pkgconf_buffer_escape`, but takes a prebuilt byte-set. + * The source and destination buffers must not overlap. + * + * :param pkgconf_buffer_t *dest: The destination buffer. + * :param pkgconf_buffer_t *src: The source buffer. + * :param pkgconf_charset_t *charset: The set of bytes to escape. + * :return: :code:`true` on success, :code:`false` on allocation failure. + */ +bool +pkgconf_buffer_escape_charset(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_charset_t *charset) { const char *p = pkgconf_buffer_str(src); + const char *run = p; + + if (dest == src || + buffer_storage_overlaps(dest, src->base, pkgconf_buffer_len(src) + 1)) + return false; if (!pkgconf_buffer_len(src)) return true; for (; *p; p++) { - if (pkgconf_span_contains((unsigned char) *p, spans, nspans)) - { - if (!pkgconf_buffer_push_byte(dest, '\\')) - return false; - } + if (!pkgconf_charset_contains(charset, (unsigned char) *p)) + continue; - if (!pkgconf_buffer_push_byte(dest, *p)) + if (p > run && !pkgconf_buffer_append_slice(dest, run, (size_t) (p - run))) return false; + + if (!pkgconf_buffer_push_byte(dest, '\\')) + return false; + + run = p; } + if (p > run) + return pkgconf_buffer_append_slice(dest, run, (size_t) (p - run)); + return true; } diff --git a/contrib/pkgconf/libpkgconf/bytecode.c b/contrib/pkgconf/libpkgconf/bytecode.c index a83b7d8fe72d..2f4a1b9bc8a6 100644 --- a/contrib/pkgconf/libpkgconf/bytecode.c +++ b/contrib/pkgconf/libpkgconf/bytecode.c @@ -64,6 +64,21 @@ pkgconf_bytecode_eval_append(pkgconf_bytecode_eval_ctx_t *ctx, pkgconf_buffer_t static bool pkgconf_bytecode_eval_internal(pkgconf_bytecode_eval_ctx_t *ctx, const pkgconf_bytecode_t *bc, pkgconf_buffer_t *out, bool *saw_sysroot); +static bool +pkgconf_bytecode_read_op(const uint8_t *p, size_t remaining, + const pkgconf_bytecode_op_t **op, size_t *op_size) +{ + if (p == NULL || remaining < sizeof(**op)) + return false; + + *op = (const pkgconf_bytecode_op_t *) p; + if ((size_t) (*op)->size > remaining - sizeof(**op)) + return false; + + *op_size = sizeof(**op) + (size_t) (*op)->size; + return true; +} + static pkgconf_variable_t * pkgconf_bytecode_eval_scan(const pkgconf_list_t *vars, const char *name, size_t nlen, unsigned int require_flags, unsigned int forbid_flags) { @@ -139,8 +154,11 @@ pkgconf_bytecode_eval_internal(pkgconf_bytecode_eval_ctx_t *ctx, const pkgconf_b if (bc == NULL || out == NULL) return false; + if (bc->len != 0 && bc->base == NULL) + return false; + const uint8_t *p = bc->base; - const uint8_t *end = bc->base + bc->len; + size_t remaining = bc->len; if (++ctx->expansions > PKGCONF_EVAL_MAX_ITERATIONS) { @@ -150,15 +168,12 @@ pkgconf_bytecode_eval_internal(pkgconf_bytecode_eval_ctx_t *ctx, const pkgconf_b return false; } - while (p < end) + while (remaining != 0) { - const pkgconf_bytecode_op_t *op = - (const pkgconf_bytecode_op_t *)p; + const pkgconf_bytecode_op_t *op; + size_t op_size; - if ((const uint8_t *)op + sizeof(*op) > end) - return false; - - if ((const uint8_t *)op + sizeof(*op) + op->size > end) + if (!pkgconf_bytecode_read_op(p, remaining, &op, &op_size)) return false; switch (op->tag) @@ -186,7 +201,8 @@ pkgconf_bytecode_eval_internal(pkgconf_bytecode_eval_ctx_t *ctx, const pkgconf_b return false; } - p = (const uint8_t *)pkgconf_bytecode_op_next(op); + p += op_size; + remaining -= op_size; } return true; @@ -301,7 +317,7 @@ void pkgconf_bytecode_from_buffer(pkgconf_bytecode_t *bc, const pkgconf_buffer_t *buf) { bc->base = (const uint8_t *)buf->base; - bc->len = (size_t)(buf->end - buf->base); + bc->len = buf->base != NULL ? (size_t)(buf->end - buf->base) : 0; } bool @@ -446,24 +462,23 @@ pkgconf_bytecode_eval_str(const pkgconf_client_t *client, const pkgconf_list_t * bool pkgconf_bytecode_references_var(const pkgconf_buffer_t *buf, const char *key) { - const uint8_t *p, *end; + const uint8_t *p; + size_t remaining; size_t klen; if (buf == NULL || key == NULL) return false; klen = strlen(key); - p = (uint8_t *) buf->base; - end = (uint8_t *) buf->end; + p = (const uint8_t *) buf->base; + remaining = pkgconf_buffer_len(buf); - while (p < end) + while (remaining != 0) { - const pkgconf_bytecode_op_t *op = (const pkgconf_bytecode_op_t *)p; + const pkgconf_bytecode_op_t *op; + size_t op_size; - if (p + sizeof(*op) > end) - return false; - - if (p + sizeof(*op) + op->size > end) + if (!pkgconf_bytecode_read_op(p, remaining, &op, &op_size)) return false; if (op->tag == PKGCONF_BYTECODE_OP_VAR) @@ -472,7 +487,8 @@ pkgconf_bytecode_references_var(const pkgconf_buffer_t *buf, const char *key) return true; } - p += sizeof(*op) + op->size; + p += op_size; + remaining -= op_size; } return false; @@ -504,17 +520,18 @@ pkgconf_bytecode_append_stream(pkgconf_buffer_t *dst, const pkgconf_buffer_t *bc bool pkgconf_bytecode_rewrite_selfrefs(pkgconf_buffer_t *out, const pkgconf_buffer_t *rhs, const char *key, const pkgconf_buffer_t *prev) { - const uint8_t *p = (uint8_t *) rhs->base; - const uint8_t *end = (uint8_t *) rhs->end; + if (out == NULL || rhs == NULL || key == NULL || prev == NULL) + return false; - while (p < end) + const uint8_t *p = (const uint8_t *) rhs->base; + size_t remaining = pkgconf_buffer_len(rhs); + + while (remaining != 0) { - const pkgconf_bytecode_op_t *op = (const pkgconf_bytecode_op_t *)p; + const pkgconf_bytecode_op_t *op; + size_t op_size; - if (p + sizeof(*op) > end) - return false; - - if (p + sizeof(*op) + op->size > end) + if (!pkgconf_bytecode_read_op(p, remaining, &op, &op_size)) return false; if (pkgconf_bytecode_op_is_selfref(op, key)) @@ -524,11 +541,12 @@ pkgconf_bytecode_rewrite_selfrefs(pkgconf_buffer_t *out, const pkgconf_buffer_t } else { - if (!pkgconf_buffer_append_slice(out, (const char *) op, sizeof(*op) + op->size)) + if (!pkgconf_buffer_append_slice(out, (const char *) op, op_size)) return false; } - p += sizeof(*op) + op->size; + p += op_size; + remaining -= op_size; } return true; diff --git a/contrib/pkgconf/libpkgconf/cache.c b/contrib/pkgconf/libpkgconf/cache.c index 4f5f3cb62b97..dcd38c413dff 100644 --- a/contrib/pkgconf/libpkgconf/cache.c +++ b/contrib/pkgconf/libpkgconf/cache.c @@ -42,37 +42,6 @@ cache_member_cmp(const void *a, const void *b) return strcmp(key, pkg->id); } -static int -cache_member_sort_cmp(const void *a, const void *b) -{ - const pkgconf_pkg_t *pkgA = *(void **) a; - const pkgconf_pkg_t *pkgB = *(void **) b; - - if (pkgA == NULL) - return 1; - - if (pkgB == NULL) - return -1; - - return strcmp(pkgA->id, pkgB->id); -} - -static void -cache_dump(const pkgconf_client_t *client) -{ - size_t i; - - PKGCONF_TRACE(client, "dumping package cache contents"); - - for (i = 0; i < client->cache_count; i++) - { - const pkgconf_pkg_t *pkg = client->cache_table[i]; - - PKGCONF_TRACE(client, SIZE_FMT_SPECIFIER": %p(%s)", - i, pkg, pkg == NULL ? "NULL" : pkg->id); - } -} - /* * !doc * @@ -127,6 +96,13 @@ pkgconf_cache_add(pkgconf_client_t *client, pkgconf_pkg_t *pkg) if (pkg == NULL) return; + pkgconf_pkg_t *cached_pkg = pkgconf_cache_lookup(client, pkg->id); + if (cached_pkg != NULL) + { + pkgconf_pkg_unref(client, cached_pkg); + return; + } + pkgconf_pkg_ref(client, pkg); pkgconf_pkg_t **new_table; @@ -148,10 +124,21 @@ pkgconf_cache_add(pkgconf_client_t *client, pkgconf_pkg_t *pkg) } client->cache_table = new_table; - client->cache_table[client->cache_count - 1] = pkg; - qsort(client->cache_table, client->cache_count, - sizeof(void *), cache_member_sort_cmp); + size_t lo = 0, hi = client->cache_count - 1; + while (lo < hi) + { + size_t mid = lo + (hi - lo) / 2; + + if (strcmp(client->cache_table[mid]->id, pkg->id) < 0) + lo = mid + 1; + else + hi = mid; + } + + memmove(&client->cache_table[lo + 1], &client->cache_table[lo], + (client->cache_count - 1 - lo) * sizeof(void *)); + client->cache_table[lo] = pkg; PKGCONF_TRACE(client, "added @%p to cache", pkg); } @@ -192,18 +179,10 @@ pkgconf_cache_remove(pkgconf_client_t *client, pkgconf_pkg_t *pkg) (*slot)->flags &= ~PKGCONF_PKG_PROPF_CACHED; pkgconf_pkg_unref(client, *slot); - *slot = NULL; - qsort(client->cache_table, client->cache_count, - sizeof(void *), cache_member_sort_cmp); - - if (client->cache_table[client->cache_count - 1] != NULL) - { - PKGCONF_TRACE(client, "end of cache table refers to %p, not NULL", - client->cache_table[client->cache_count - 1]); - cache_dump(client); - abort(); - } + size_t idx = (size_t)(slot - client->cache_table); + memmove(&client->cache_table[idx], &client->cache_table[idx + 1], + (client->cache_count - idx - 1) * sizeof(void *)); client->cache_count--; if (client->cache_count > 0) diff --git a/contrib/pkgconf/libpkgconf/client.c b/contrib/pkgconf/libpkgconf/client.c index 3e61a0fc1445..3b1ca7239e46 100644 --- a/contrib/pkgconf/libpkgconf/client.c +++ b/contrib/pkgconf/libpkgconf/client.c @@ -108,11 +108,38 @@ pkgconf_client_dir_list_build(pkgconf_client_t *client, const pkgconf_cross_pers void pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler) { + pkgconf_client_options_t options = { + .error_handler = error_handler, + .error_handler_data = error_handler_data, + .personality = personality, + .client_data = client_data, + .environ_lookup_handler = environ_lookup_handler, + }; + + pkgconf_client_init_with_options(client, &options); +} + +/* + * !doc + * + * .. c:function:: void pkgconf_client_init_with_options(pkgconf_client_t *client, const pkgconf_client_options_t *options) + * + * Initialise a pkgconf client object using an options structure. + * + * :param pkgconf_client_t* client: The client to initialise. + * :param pkgconf_client_options_t* options: The options used to configure the client. + * :return: nothing + */ +void +pkgconf_client_init_with_options(pkgconf_client_t *client, const pkgconf_client_options_t *options) +{ + const pkgconf_cross_personality_t *personality = options->personality; + client->personality = personality; - client->client_data = client_data; - client->environ_lookup_handler = environ_lookup_handler; - client->error_handler_data = error_handler_data; - client->error_handler = error_handler; + client->client_data = options->client_data; + client->environ_lookup_handler = options->environ_lookup_handler; + client->error_handler_data = options->error_handler_data; + client->error_handler = options->error_handler; client->auditf = NULL; client->cache_table = NULL; client->cache_count = 0; @@ -122,10 +149,12 @@ pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error pkgconf_client_set_trace_handler(client, NULL, NULL); #endif - if (client->unveil_handler == NULL) + if (options->unveil_handler != NULL) + pkgconf_client_set_unveil_handler(client, options->unveil_handler); + else if (client->unveil_handler == NULL) pkgconf_client_set_unveil_handler(client, NULL); - pkgconf_client_set_error_handler(client, error_handler, error_handler_data); + pkgconf_client_set_error_handler(client, options->error_handler, options->error_handler_data); pkgconf_client_set_warn_handler(client, NULL, NULL); pkgconf_client_set_sysroot_dir(client, personality->sysroot_dir); @@ -183,12 +212,37 @@ pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error */ pkgconf_client_t * pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler) +{ + pkgconf_client_options_t options = { + .error_handler = error_handler, + .error_handler_data = error_handler_data, + .personality = personality, + .client_data = client_data, + .environ_lookup_handler = environ_lookup_handler, + }; + + return pkgconf_client_new_with_options(&options); +} + +/* + * !doc + * + * .. c:function:: pkgconf_client_t* pkgconf_client_new_with_options(const pkgconf_client_options_t *options) + * + * Allocate and initialise a pkgconf client object using an options structure. + * + * :param pkgconf_client_options_t* options: The options used to configure the client. + * :return: A pkgconf client object. + * :rtype: pkgconf_client_t* + */ +pkgconf_client_t * +pkgconf_client_new_with_options(const pkgconf_client_options_t *options) { pkgconf_client_t *out = calloc(1, sizeof(pkgconf_client_t)); if (out == NULL) return NULL; - pkgconf_client_init(out, error_handler, error_handler_data, personality, client_data, environ_lookup_handler); + pkgconf_client_init_with_options(out, options); return out; } @@ -304,6 +358,11 @@ pkgconf_client_set_sysroot_dir(pkgconf_client_t *client, const char *sysroot_dir client->sysroot_dir = sysroot_dir != NULL ? strdup(sysroot_dir) : NULL; + /* normalize separators so the sysroot compares equal to the (already + * canonicalized) paths it is matched against during injection */ + if (client->sysroot_dir != NULL) + pkgconf_path_normalize_separators(client->sysroot_dir); + PKGCONF_TRACE(client, "set sysroot_dir to: %s", client->sysroot_dir != NULL ? client->sysroot_dir : ""); pkgconf_tuple_add_global(client, "pc_sysrootdir", client->sysroot_dir != NULL ? client->sysroot_dir : ""); @@ -348,6 +407,9 @@ pkgconf_client_set_buildroot_dir(pkgconf_client_t *client, const char *buildroot client->buildroot_dir = buildroot_dir != NULL ? strdup(buildroot_dir) : NULL; + if (client->buildroot_dir != NULL) + pkgconf_path_normalize_separators(client->buildroot_dir); + PKGCONF_TRACE(client, "set buildroot_dir to: %s", client->buildroot_dir != NULL ? client->buildroot_dir : ""); pkgconf_tuple_add_global(client, "pc_top_builddir", client->buildroot_dir != NULL ? client->buildroot_dir : "$(top_builddir)"); @@ -736,6 +798,8 @@ pkgconf_client_set_unveil_handler(pkgconf_client_t *client, pkgconf_unveil_handl PKGCONF_TRACE(client, "installing default unveil handler"); client->unveil_handler = default_unveil_handler; } + else + PKGCONF_TRACE(client, "installing custom unveil handler"); } #ifndef PKGCONF_LITE @@ -772,12 +836,6 @@ pkgconf_client_set_trace_handler(pkgconf_client_t *client, pkgconf_error_handler { client->trace_handler = trace_handler; client->trace_handler_data = trace_handler_data; - - if (client->trace_handler == NULL) - { - client->trace_handler = pkgconf_default_error_handler; - PKGCONF_TRACE(client, "installing default trace handler"); - } } #endif @@ -825,7 +883,10 @@ pkgconf_client_preload_path(pkgconf_client_t *client, const char *path) if (pkg == NULL) return false; - return pkgconf_client_preload_one(client, pkg); + bool ret = pkgconf_client_preload_one(client, pkg); + pkgconf_pkg_unref(client, pkg); + + return ret; } /* @@ -895,7 +956,7 @@ pkgconf_client_set_output(pkgconf_client_t *client, pkgconf_output_t *output) * Looks up an environmental variable which may be mocked, otherwise fetches * from the main environment. * - * :param pkgconf_client_t* client: yhe client object to use for looking up environmental variables. + * :param pkgconf_client_t* client: the client object to use for looking up environmental variables. * :param char* key: the environmental variable to look up. * :return: the environmental variable contents else NULL * :rtype: const char* diff --git a/contrib/pkgconf/libpkgconf/config.h.meson b/contrib/pkgconf/libpkgconf/config.h.meson index 5add4e9e301d..08aca0faa712 100644 --- a/contrib/pkgconf/libpkgconf/config.h.meson +++ b/contrib/pkgconf/libpkgconf/config.h.meson @@ -1,11 +1,5 @@ /* libpkgconf/config.h.in. Generated from configure.ac by autoheader. */ -/* Define to 1 if you have the `strlcat' function. */ -#mesondefine HAVE_STRLCAT - -/* Define to 1 if you have the `strlcpy' function. */ -#mesondefine HAVE_STRLCPY - /* Define to 1 if you have the `strndup' function. */ #mesondefine HAVE_STRNDUP @@ -24,36 +18,30 @@ /* Define to 1 if you have the `unveil' function. */ #mesondefine HAVE_DECL_UNVEIL +/* Define to 1 if you have the `readlinkat' function. */ +#mesondefine HAVE_DECL_READLINKAT + +/* Define to 1 if you have the `mkdtemp' function. */ +#mesondefine HAVE_DECL_MKDTEMP + +/* Define to 1 if you have the `getc_unlocked' function. */ +#mesondefine HAVE_DECL_GETC_UNLOCKED + /* Define to 1 if you have the `nl_langinfo_l' function. */ #mesondefine HAVE_DECL_NL_LANGINFO_L -/* Name of package */ -#mesondefine PACKAGE - /* Define to the address where bug reports for this package should be sent. */ #mesondefine PACKAGE_BUGREPORT /* Define to the full name of this package. */ #mesondefine PACKAGE_NAME -/* Define to the full name and version of this package. */ -#mesondefine PACKAGE_STRING - /* Define to the one symbol short name of this package. */ #mesondefine PACKAGE_TARNAME -/* Define to the home page for this package. */ -#mesondefine PACKAGE_URL - /* Define to the version of this package. */ #mesondefine PACKAGE_VERSION -/* Define to 1 if you have the ANSI C header files. */ -#mesondefine STDC_HEADERS - -/* Version number of package */ -#mesondefine VERSION - /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE # define _DARWIN_USE_64_BIT_INODE 1 diff --git a/contrib/pkgconf/libpkgconf/dependency.c b/contrib/pkgconf/libpkgconf/dependency.c index ce5237f2c154..810c885237e5 100644 --- a/contrib/pkgconf/libpkgconf/dependency.c +++ b/contrib/pkgconf/libpkgconf/dependency.c @@ -43,10 +43,12 @@ static inline const char * dependency_to_buf(const pkgconf_dependency_t *dep, pkgconf_buffer_t *buf) { pkgconf_buffer_reset(buf); - pkgconf_buffer_append(buf, dep->package); + if (!pkgconf_buffer_append(buf, dep->package)) + return NULL; - if (dep->version != NULL) - pkgconf_buffer_append_fmt(buf, " %s %s", pkgconf_pkg_get_comparator(dep), dep->version); + if (dep->version != NULL && + !pkgconf_buffer_append_fmt(buf, " %s %s", pkgconf_pkg_get_comparator(dep), dep->version)) + return NULL; return pkgconf_buffer_str(buf); } @@ -71,18 +73,34 @@ find_colliding_dependency(const pkgconf_dependency_t *dep, const pkgconf_list_t return NULL; } +static inline const char * +dependency_trace_str(const pkgconf_client_t *client, const pkgconf_dependency_t *dep, pkgconf_buffer_t *buf) +{ +#ifndef PKGCONF_LITE + const char *str; + + if (pkgconf_client_get_trace_handler(client) == NULL) + return dep->package; + + str = dependency_to_buf(dep, buf); + return str != NULL ? str : dep->package; +#else + return dep->package; +#endif +} + static inline pkgconf_dependency_t * add_or_replace_dependency_node(pkgconf_client_t *client, pkgconf_dependency_t *dep, pkgconf_list_t *list) { pkgconf_buffer_t depbuf = PKGCONF_BUFFER_INITIALIZER; pkgconf_dependency_t *dep2 = find_colliding_dependency(dep, list); - const char *depstr = dependency_to_buf(dep, &depbuf); + const char *depstr = dependency_trace_str(client, dep, &depbuf); /* there is already a node in the graph which describes this dependency */ if (dep2 != NULL) { pkgconf_buffer_t depbuf2 = PKGCONF_BUFFER_INITIALIZER; - const char *depstr2 = dependency_to_buf(dep2, &depbuf2); + const char *depstr2 = dependency_trace_str(client, dep2, &depbuf2); PKGCONF_TRACE(client, "dependency collision: [%s/%x] -- [%s/%x]", depstr, dep->flags, depstr2, dep2->flags); @@ -149,7 +167,14 @@ pkgconf_dependency_addraw(pkgconf_client_t *client, pkgconf_list_t *list, const } if (version_sz != 0) + { dep->version = pkgconf_strndup(version, version_sz); + if (dep->version == NULL) + { + pkgconf_dependency_free_one(dep); + return NULL; + } + } dep->compare = compare; dep->flags = flags; @@ -413,8 +438,10 @@ pkgconf_dependency_parse_str(pkgconf_client_t *client, pkgconf_list_t *deplist_h if (PKGCONF_IS_OPERATOR_CHAR(*ptr)) break; - pkgconf_buffer_reset(&cmpname); - pkgconf_buffer_append_slice(&cmpname, opstart, ptr - opstart); + pkgconf_buffer_rewind(&cmpname); + if (!pkgconf_buffer_append_slice(&cmpname, opstart, ptr - opstart)) + goto out; + compare = pkgconf_pkg_comparator_lookup_by_name(pkgconf_buffer_str(&cmpname)); state = AFTER_OPERATOR; // fallthrough @@ -439,7 +466,7 @@ pkgconf_dependency_parse_str(pkgconf_client_t *client, pkgconf_list_t *deplist_h compare = PKGCONF_CMP_ANY; package_sz = 0; opstart = NULL; - pkgconf_buffer_reset(&cmpname); + pkgconf_buffer_rewind(&cmpname); } if (state == OUTSIDE_MODULE) @@ -508,7 +535,14 @@ pkgconf_dependency_copy(pkgconf_client_t *client, const pkgconf_dependency_t *de } if (dep->version != NULL) + { new_dep->version = strdup(dep->version); + if (new_dep->version == NULL) + { + pkgconf_dependency_free_one(new_dep); + return NULL; + } + } new_dep->compare = dep->compare; new_dep->flags = dep->flags; diff --git a/contrib/pkgconf/libpkgconf/fileio.c b/contrib/pkgconf/libpkgconf/fileio.c index 2acec22aaee6..638303c9e50a 100644 --- a/contrib/pkgconf/libpkgconf/fileio.c +++ b/contrib/pkgconf/libpkgconf/fileio.c @@ -15,107 +15,81 @@ * from the use of this software. */ +#include #include #include -#define push_or_return_fail(buf, c) \ - do { if (!pkgconf_buffer_push_byte((buf), (char) (c))) return false; } while (0) - -#define trim_or_return_fail(buf) \ - do { if (!pkgconf_buffer_trim_byte((buf))) return false; } while (0) +#if HAVE_DECL_GETC_UNLOCKED +# define pkgconf_getc(stream) getc_unlocked(stream) +#else +# define pkgconf_getc(stream) getc(stream) +#endif bool pkgconf_fgetline(pkgconf_buffer_t *buffer, FILE *stream) { bool quoted = false; bool got_data = false; - char in[PKGCONF_ITEM_SIZE]; - long unread = 0; + char run[256]; + size_t runlen = 0; + int c; - while (fgets(in, sizeof in, stream) != NULL) + while ((c = pkgconf_getc(stream)) != EOF) { - char *p = in; - got_data = true; - while (*p != '\0') + if (c == '\\' && !quoted) { - unsigned char c = (unsigned char) *p++; + quoted = true; + continue; + } - if (c == '\\' && !quoted) + if (c == '\n') + { + if (quoted) { - quoted = true; + quoted = false; continue; } - else if (c == '\n') - { - if (quoted) - { - quoted = false; - continue; - } - else - push_or_return_fail(buffer, (char) c); - goto done; - } - else if (c == '\r') - { - if (*p == '\n') - { - p++; - } - else if (*p == '\0') - { - /* - * The matching '\n' may not have been read into `in` - * yet if '\r' landed exactly on the fgets() buffer - * boundary. Peek the real stream so a split CRLF - * isn't misparsed as two lines. - */ - int next = getc(stream); - - if (next != '\n' && next != EOF && ungetc(next, stream) == EOF) - return false; - } - - if (quoted) - { - quoted = false; - continue; - } - - push_or_return_fail(buffer, '\n'); - /* unlike '\n', a lone '\r' doesn't bound the fgets() call above */ - unread = (long) strlen(p); - goto done; - } - else - { - if (quoted) - { - push_or_return_fail(buffer, '\\'); - quoted = false; - } - - push_or_return_fail(buffer, (char) c); - } + break; } + + if (c == '\r') + { + int next = pkgconf_getc(stream); + + if (next != '\n' && next != EOF && ungetc(next, stream) == EOF) + return false; + + if (quoted) + { + quoted = false; + continue; + } + + break; + } + + if (runlen > sizeof run - 2) + { + if (!pkgconf_buffer_append_slice(buffer, run, runlen)) + return false; + + runlen = 0; + } + + if (quoted) + { + run[runlen++] = '\\'; + quoted = false; + } + + run[runlen++] = (char) c; } -done: - if (unread > 0 && fseek(stream, -unread, SEEK_CUR) != 0) + if (runlen != 0 && !pkgconf_buffer_append_slice(buffer, run, runlen)) return false; - /* Remove newline character. */ - if (pkgconf_buffer_lastc(buffer) == '\n') - trim_or_return_fail(buffer); - - if (pkgconf_buffer_lastc(buffer) == '\r') - trim_or_return_fail(buffer); - - if (!got_data) - return false; - - return !ferror(stream); + return got_data && !ferror(stream); } diff --git a/contrib/pkgconf/libpkgconf/fragment.c b/contrib/pkgconf/libpkgconf/fragment.c index ab649c09db96..86a9210613ae 100644 --- a/contrib/pkgconf/libpkgconf/fragment.c +++ b/contrib/pkgconf/libpkgconf/fragment.c @@ -69,8 +69,14 @@ pkgconf_fragment_is_greedy(const char *string) return false; } -static inline bool -pkgconf_fragment_should_check_sysroot(const char *string) +/* + * Length of the flag introducing a path which sysroot may be injected into, or + * 0 if this is not such a flag. The length matters as well as the answer: the + * path starts there, and it is the path which has to be judged, not the whole + * fragment. + */ +static inline size_t +pkgconf_fragment_sysroot_path_offset(const char *string) { static const struct pkgconf_fragment_check check_fragments[] = { {"-F", 2}, @@ -81,13 +87,57 @@ pkgconf_fragment_should_check_sysroot(const char *string) }; if (*string != '-') - return false; + return 0; for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(check_fragments); i++) if (!strncmp(string, check_fragments[i].token, check_fragments[i].len)) - return true; + return check_fragments[i].len; - return false; + return 0; +} + +/* + * Length of a flag which names its path as a separate argument, or 0 if this is + * not one of those. + */ +static inline size_t +pkgconf_fragment_separate_path_offset(const char *string) +{ + static const struct pkgconf_fragment_check check_fragments[] = { + {"-isystem", 8}, + {"-idirafter", 10}, + }; + + if (*string != '-') + return 0; + + for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(check_fragments); i++) + if (!strncmp(string, check_fragments[i].token, check_fragments[i].len)) + return check_fragments[i].len; + + return 0; +} + +/* + * Whether `path` already lies under the sysroot, in which case injecting it + * again would only produce a doubled prefix. + * + * This is read off the path rather than remembered from the expansion which + * produced it. A fragment carries everything the question needs, so the answer + * holds per fragment however the .pc file arrived at the path -- whether the + * sysroot came from ${pc_sysrootdir}, from a variable which happens to sit under + * it, or was written out longhand -- and survives the path being split out of a + * larger expansion, where provenance would not. + */ +static inline bool +pkgconf_fragment_under_sysroot(const pkgconf_client_t *client, const char *path) +{ + size_t len = strlen(client->sysroot_dir); + + if (strncmp(path, client->sysroot_dir, len)) + return false; + + return path[len] == '/' || path[len] == '\0'; } static inline bool @@ -190,6 +240,26 @@ pkgconf_fragment_is_special(const char *string) return pkgconf_fragment_is_unmergeable(string); } +static pkgconf_fragment_t * +fragment_new(char type, const char *data) +{ + size_t datalen = data != NULL ? strlen(data) : 0; + pkgconf_fragment_t *frag = calloc(1, sizeof(*frag) + (data != NULL ? datalen + 1 : 0)); + + if (frag == NULL) + return NULL; + + frag->type = type; + + if (data != NULL) + { + frag->data = (char *)(frag + 1); + memcpy(frag->data, data, datalen + 1); + } + + return frag; +} + /* * !doc * @@ -211,13 +281,10 @@ pkgconf_fragment_insert(pkgconf_client_t *client, pkgconf_list_t *list, char typ pkgconf_fragment_t *frag; - frag = calloc(1, sizeof(pkgconf_fragment_t)); + frag = fragment_new(type, data); if (frag == NULL) return; - frag->type = type; - frag->data = strdup(data); - if (tail) { pkgconf_node_insert_tail(&frag->iter, frag, list); @@ -228,10 +295,11 @@ pkgconf_fragment_insert(pkgconf_client_t *client, pkgconf_list_t *list, char typ } static bool -should_inject_sysroot(const pkgconf_client_t *client, const char *string, bool saw_sysroot, unsigned int flags) +should_inject_sysroot(const pkgconf_client_t *client, const char *string, unsigned int flags) { - /* emulating original pkg-config: we never inject sysroot */ - if (client->flags & PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES) + size_t offset; + + if (client->flags & PKGCONF_PKG_PKGF_NO_SYSROOT_INJECTION) return false; /* we never automatically inject sysroot on -uninstalled packages */ @@ -245,26 +313,17 @@ should_inject_sysroot(const pkgconf_client_t *client, const char *string, bool s if (client->sysroot_dir == NULL) return false; - if (saw_sysroot) + offset = pkgconf_fragment_sysroot_path_offset(string); + if (offset == 0) return false; - if (!pkgconf_fragment_should_check_sysroot(string)) - return false; - - if (!strncmp(string + 2, client->sysroot_dir, strlen(client->sysroot_dir)) && - *(string + 2 + strlen(client->sysroot_dir)) == '/') - { - return false; - } - - return true; + return !pkgconf_fragment_under_sysroot(client, string + offset); } static bool -should_inject_sysroot_child(const pkgconf_client_t *client, const pkgconf_fragment_t *last, const char *string, bool saw_sysroot, unsigned int flags) +should_inject_sysroot_child(const pkgconf_client_t *client, const pkgconf_fragment_t *last, const char *string, unsigned int flags) { - /* emulating original pkg-config: we never inject sysroot */ - if (client->flags & PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES) + if (client->flags & PKGCONF_PKG_PKGF_NO_SYSROOT_INJECTION) return false; /* we never automatically inject sysroot on -uninstalled packages */ @@ -284,77 +343,49 @@ should_inject_sysroot_child(const pkgconf_client_t *client, const pkgconf_fragme if (client->sysroot_dir == NULL) return false; - if (saw_sysroot) + /* the flag is the preceding fragment; this one is the bare path it takes. + * a flag which has already taken its argument takes no further ones, so + * what follows is a fragment in its own right and not a path at all. */ + if (last->flags & PKGCONF_PKG_FRAGF_TERMINATED) return false; - if (!pkgconf_fragment_should_check_sysroot(last->data)) + if (pkgconf_fragment_sysroot_path_offset(last->data) == 0) return false; - if (!strncmp(string, client->sysroot_dir, strlen(client->sysroot_dir)) && - *(string + strlen(client->sysroot_dir)) == '/') - { - return false; - } - - return true; -} - -static inline bool -fragment_is_unquoted_var(const char *value) -{ - size_t len; - - if (value == NULL) - return false; - - len = strlen(value); - - if (len < 4 || value[0] != '$') - return false; - - if (value[1] == '{' && value[len - 1] == '}') - return true; - - return false; + return !pkgconf_fragment_under_sysroot(client, string); } /* - * !doc - * - * .. c:function:: void pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string, unsigned int flags) - * - * Adds a `fragment` of text to a `fragment list`, possibly modifying the fragment if a sysroot is set. - * - * :param pkgconf_client_t* client: The pkgconf client being accessed. - * :param pkgconf_list_t* list: The fragment list. - * :param char* string: The string of text to add as a fragment to the fragment list. - * :param uint flags: Parsing-related flags for the package. - * :return: nothing + * Insert an already-expanded fragment string into the list. No variable + * substitution is performed here: `string` is taken verbatim, so this must + * only be called with input that has already been through the bytecode + * evaluator. Whether sysroot injection is still wanted is read off `string` + * itself; see pkgconf_fragment_under_sysroot. */ -void -pkgconf_fragment_add(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value, unsigned int flags) +static bool +fragment_insert_evaluated(pkgconf_client_t *client, pkgconf_list_t *list, const char *string, unsigned int flags) { pkgconf_list_t *target = list; + pkgconf_fragment_t *terminate_parent = NULL; pkgconf_fragment_t *frag; - pkgconf_buffer_t evalbuf = PKGCONF_BUFFER_INITIALIZER; - bool saw_sysroot = false; - char *string; + size_t separate; - if (!pkgconf_bytecode_eval_str_to_buf(client, vars, value, &saw_sysroot, &evalbuf)) + if (string == NULL || *string == '\0') + return true; + + /* A .pc file may join one of these flags to its path. That names the same + * thing as writing them apart, so split it back apart and let there be one + * spelling of it in a fragment list: the flag, and the path it takes. */ + separate = pkgconf_fragment_separate_path_offset(string); + if (separate != 0 && string[separate] != '\0') { - pkgconf_buffer_finalize(&evalbuf); - return; - } + pkgconf_buffer_t flagbuf = PKGCONF_BUFFER_INITIALIZER; + bool ok = pkgconf_buffer_append_slice(&flagbuf, string, separate) && + fragment_insert_evaluated(client, list, pkgconf_buffer_str(&flagbuf), flags) && + fragment_insert_evaluated(client, list, string + separate, flags); - string = pkgconf_buffer_freeze(&evalbuf); - if (string == NULL) - return; - - if (fragment_is_unquoted_var(value)) - { - pkgconf_fragment_parse(client, list, vars, string, flags); - free(string); - return; + pkgconf_buffer_finalize(&flagbuf); + return ok; } if (list->tail != NULL && list->tail->data != NULL && @@ -371,64 +402,193 @@ pkgconf_fragment_add(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_lis target = &parent->children; if (pkgconf_fragment_is_terminus(parent->data, string)) - parent->flags |= PKGCONF_PKG_FRAGF_TERMINATED; + terminate_parent = parent; PKGCONF_TRACE(client, "adding fragment as child to list @%p", target); } } - frag = calloc(1, sizeof(pkgconf_fragment_t)); + /* Compute the final data string first (borrowing sysroot_buf when we have to + * prepend the sysroot), then hand it to fragment_new(), which copies it + * inline. data == NULL here means an allocation/append failure. */ + { + char type = 0; + const char *data = NULL; + pkgconf_buffer_t sysroot_buf = PKGCONF_BUFFER_INITIALIZER; + + if (strlen(string) > 1 && !pkgconf_fragment_is_special(string)) + { + type = *(string + 1); + + if (should_inject_sysroot(client, string, flags)) + { + if (pkgconf_buffer_append(&sysroot_buf, client->sysroot_dir) && + pkgconf_buffer_append(&sysroot_buf, string + 2)) + data = pkgconf_buffer_str(&sysroot_buf); + } + else + data = string + 2; + } + else + { + type = 0; + + if (client->sysroot_dir != NULL && list->tail != NULL && list->tail->data != NULL && + should_inject_sysroot_child(client, list->tail->data, string, flags)) + { + if (pkgconf_buffer_append(&sysroot_buf, client->sysroot_dir) && + pkgconf_buffer_append(&sysroot_buf, string)) + data = pkgconf_buffer_str(&sysroot_buf); + } + else + data = string; + } + + frag = data != NULL ? fragment_new(type, data) : NULL; + pkgconf_buffer_finalize(&sysroot_buf); + } + if (frag == NULL) { PKGCONF_TRACE(client, "failed to add new fragment due to allocation failure to list @%p", target); - free(string); - return; + return false; } - if (strlen(string) > 1 && !pkgconf_fragment_is_special(string)) - { - frag->type = *(string + 1); - - if (should_inject_sysroot(client, string, saw_sysroot, flags)) - { - pkgconf_buffer_t sysroot_buf = PKGCONF_BUFFER_INITIALIZER; - - pkgconf_buffer_append(&sysroot_buf, client->sysroot_dir); - pkgconf_buffer_append(&sysroot_buf, string + 2); - - frag->data = pkgconf_buffer_freeze(&sysroot_buf); - } - else - frag->data = strdup(string + 2); - + if (frag->type) PKGCONF_TRACE(client, "added fragment {%c, '%s'} to list @%p", frag->type, frag->data, list); - } else - { - if (client->sysroot_dir != NULL && list->tail != NULL && list->tail->data != NULL) - { - pkgconf_fragment_t *last = list->tail->data; - - if (should_inject_sysroot_child(client, last, string, saw_sysroot, flags)) - { - pkgconf_buffer_t sysroot_buf = PKGCONF_BUFFER_INITIALIZER; - - pkgconf_buffer_append(&sysroot_buf, client->sysroot_dir); - pkgconf_buffer_append(&sysroot_buf, string); - - free(string); - string = pkgconf_buffer_freeze(&sysroot_buf); - } - } - - frag->type = 0; - frag->data = strdup(string); - PKGCONF_TRACE(client, "created special fragment {'%s'} in list @%p", frag->data, target); - } pkgconf_node_insert_tail(&frag->iter, frag, target); - free(string); + if (terminate_parent != NULL) + terminate_parent->flags |= PKGCONF_PKG_FRAGF_TERMINATED; + + return true; +} + +/* + * Split a string into whitespace-delimited fragments, honouring shell quoting + * and greedy flags (e.g. "-I /usr/include" -> "-I/usr/include"). + * + * When `evaluate` is true, `value` is a property as the .pc file spells it and + * each token is handed to pkgconf_fragment_add to be expanded. Splitting it + * only settles where the tokens end, so the quoting is left in place for the + * pass over the expansion to consume. + * + * When `evaluate` is false, `value` is the expansion of one such token. This is + * where the quoting is consumed, once, over text which is otherwise finished, + * and the tokens are inserted as they stand. It must not evaluate again, lest + * an expansion yielding a literal "${...}" (via a "$$" escape) recurse forever. + */ +static bool +fragment_split(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value, unsigned int flags, bool evaluate) +{ + int i, ret, argc; + char **argv; + + ret = evaluate + ? pkgconf_argv_split_raw(value, &argc, &argv) + : pkgconf_argv_split(value, &argc, &argv); + if (ret < 0) + { + PKGCONF_TRACE(client, "unable to parse fragment string [%s]", value); + return false; + } + + for (i = 0; i < argc; i++) + { + const char *token; + pkgconf_buffer_t greedybuf = PKGCONF_BUFFER_INITIALIZER; + bool ok; + + if (argv[i] == NULL) + { + PKGCONF_TRACE(client, "parsed fragment string is inconsistent: argc = %d while argv[%d] == NULL", argc, i); + pkgconf_argv_free(argv); + return false; + } + + token = argv[i]; + + PKGCONF_TRACE(client, "processing [%s]", argv[i]); + + if (pkgconf_fragment_is_greedy(argv[i]) && i + 1 < argc) + { + if (!pkgconf_buffer_append(&greedybuf, argv[i]) || + !pkgconf_buffer_append(&greedybuf, argv[i + 1])) + { + pkgconf_buffer_finalize(&greedybuf); + pkgconf_argv_free(argv); + return false; + } + + token = pkgconf_buffer_str(&greedybuf); + + /* skip over next arg as we combined them */ + i++; + } + + if (evaluate) + ok = pkgconf_fragment_add(client, list, vars, token, flags); + else + ok = fragment_insert_evaluated(client, list, token, flags); + + pkgconf_buffer_finalize(&greedybuf); + + if (!ok) + { + pkgconf_argv_free(argv); + return false; + } + } + + pkgconf_argv_free(argv); + + return true; +} + +/* + * !doc + * + * .. c:function:: bool pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string, unsigned int flags) + * + * Adds a `fragment` of text to a `fragment list`, possibly modifying the fragment if a sysroot is set. + * + * :param pkgconf_client_t* client: The pkgconf client being accessed. + * :param pkgconf_list_t* list: The fragment list. + * :param char* string: The string of text to add as a fragment to the fragment list. + * :param uint flags: Parsing-related flags for the package. + * :return: true on success, false on parse error or allocation failure + */ +bool +pkgconf_fragment_add(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value, unsigned int flags) +{ + pkgconf_buffer_t evalbuf = PKGCONF_BUFFER_INITIALIZER; + bool ret; + + if (!pkgconf_bytecode_eval_str_to_buf(client, vars, value, NULL, &evalbuf)) + { + pkgconf_buffer_finalize(&evalbuf); + return false; + } + + if (pkgconf_buffer_len(&evalbuf) == 0) + { + pkgconf_buffer_finalize(&evalbuf); + return true; + } + + /* fragment_split() only reads the expanded string, so hand it the buffer + * contents directly rather than freezing (copying) them out. + * + * The expansion is split rather than taken whole: the quoting it carries is + * consumed there, and a value may in any case expand to several + * whitespace-separated fragments. + */ + ret = fragment_split(client, list, vars, pkgconf_buffer_str(&evalbuf), flags, false); + + pkgconf_buffer_finalize(&evalbuf); + return ret; } static inline pkgconf_fragment_t * @@ -458,6 +618,99 @@ pkgconf_fragment_lookup(pkgconf_list_t *list, const pkgconf_fragment_t *base) return NULL; } +/* Order fragments by (type, data) so that the cursor index can be searched + * with bsearch(). NULL data sorts before any non-NULL data of the same type. */ +static int +fragment_index_cmp(const void *a, const void *b) +{ + const pkgconf_fragment_t *fa = *(pkgconf_fragment_t * const *) a; + const pkgconf_fragment_t *fb = *(pkgconf_fragment_t * const *) b; + + if (fa->type != fb->type) + return (unsigned char) fa->type < (unsigned char) fb->type ? -1 : 1; + + if (fa->data == NULL || fb->data == NULL) + { + if (fa->data == fb->data) + return 0; + + return fa->data == NULL ? -1 : 1; + } + + return strcmp(fa->data, fb->data); +} + +static pkgconf_fragment_t * +fragment_index_lookup(const pkgconf_fragment_cursor_t *cursor, const pkgconf_fragment_t *base) +{ + pkgconf_fragment_t **found; + + if (cursor->count == 0) + return NULL; + + found = bsearch(&base, cursor->index, cursor->count, sizeof(void *), fragment_index_cmp); + return found != NULL ? *found : NULL; +} + +static bool +fragment_index_insert(pkgconf_fragment_cursor_t *cursor, pkgconf_fragment_t *frag) +{ + size_t lo = 0, hi = cursor->count; + + if (cursor->count == cursor->alloc) + { + size_t newalloc = cursor->alloc != 0 ? cursor->alloc * 2 : 16; + pkgconf_fragment_t **newindex = pkgconf_reallocarray(cursor->index, newalloc, sizeof(void *)); + + if (newindex == NULL) + return false; + + cursor->index = newindex; + cursor->alloc = newalloc; + } + + while (lo < hi) + { + size_t mid = lo + (hi - lo) / 2; + + if (fragment_index_cmp(&cursor->index[mid], &frag) < 0) + lo = mid + 1; + else + hi = mid; + } + + memmove(&cursor->index[lo + 1], &cursor->index[lo], (cursor->count - lo) * sizeof(void *)); + cursor->index[lo] = frag; + cursor->count++; + + return true; +} + +static void +fragment_index_remove(pkgconf_fragment_cursor_t *cursor, const pkgconf_fragment_t *frag) +{ + pkgconf_fragment_t **found = bsearch(&frag, cursor->index, cursor->count, sizeof(void *), fragment_index_cmp); + size_t idx; + + if (found == NULL) + return; + + idx = (size_t) (found - cursor->index); + memmove(&cursor->index[idx], &cursor->index[idx + 1], (cursor->count - idx - 1) * sizeof(void *)); + cursor->count--; +} + +/* Look up an existing fragment matching `base`: via the cursor's sorted index + * when one is provided, otherwise a linear scan of the list. */ +static inline pkgconf_fragment_t * +fragment_lookup(pkgconf_list_t *list, const pkgconf_fragment_cursor_t *cursor, const pkgconf_fragment_t *base) +{ + if (cursor != NULL) + return fragment_index_lookup(cursor, base); + + return pkgconf_fragment_lookup(list, base); +} + static inline bool pkgconf_fragment_can_merge_back(const pkgconf_fragment_t *base, unsigned int flags, bool is_private) { @@ -499,7 +752,7 @@ pkgconf_fragment_can_merge(const pkgconf_fragment_t *base, unsigned int flags, b } static inline pkgconf_fragment_t * -pkgconf_fragment_exists(pkgconf_list_t *list, const pkgconf_fragment_t *base, unsigned int flags, bool is_private) +pkgconf_fragment_exists(pkgconf_list_t *list, const pkgconf_fragment_cursor_t *cursor, const pkgconf_fragment_t *base, unsigned int flags, bool is_private) { if (!pkgconf_fragment_can_merge_back(base, flags, is_private)) return NULL; @@ -507,7 +760,7 @@ pkgconf_fragment_exists(pkgconf_list_t *list, const pkgconf_fragment_t *base, un if (!pkgconf_fragment_can_merge(base, flags, is_private)) return NULL; - return pkgconf_fragment_lookup(list, base); + return fragment_lookup(list, cursor, base); } static inline bool @@ -568,6 +821,68 @@ pkgconf_fragment_has_system_dir(const pkgconf_client_t *client, const pkgconf_fr return pkgconf_path_match_list(frag->data, check_paths); } +static bool +pkgconf_fragment_copy_node(const pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_fragment_cursor_t *cursor, const pkgconf_fragment_t *base, bool is_private); + +static bool +pkgconf_fragment_copy_list_node(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base) +{ + pkgconf_node_t *node; + + PKGCONF_FOREACH_LIST_ENTRY(base->head, node) + { + pkgconf_fragment_t *frag = node->data; + + /* children are copied into their own (small) list, which is never + * indexed, so no cursor is threaded down here. */ + if (!pkgconf_fragment_copy_node(client, list, NULL, frag, true)) + return false; + } + + return true; +} + +static bool +pkgconf_fragment_copy_node(const pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_fragment_cursor_t *cursor, const pkgconf_fragment_t *base, bool is_private) +{ + pkgconf_fragment_t *old_frag = NULL; + pkgconf_fragment_t *frag; + + if ((old_frag = pkgconf_fragment_exists(list, cursor, base, client->flags, is_private)) != NULL) + { + if (!pkgconf_fragment_should_merge(old_frag)) + old_frag = NULL; + } + else if (!is_private && !pkgconf_fragment_can_merge_back(base, client->flags, is_private) && (fragment_lookup(list, cursor, base) != NULL)) + return true; + + frag = fragment_new(base->type, base->data); + if (frag == NULL) + return false; + + if (!pkgconf_fragment_copy_list_node(client, &frag->children, &base->children)) + { + pkgconf_fragment_free(&frag->children); + free(frag); + return false; + } + + if (old_frag != NULL) + { + if (cursor != NULL) + fragment_index_remove(cursor, old_frag); + + pkgconf_fragment_delete(list, old_frag); + } + + pkgconf_node_insert_tail(&frag->iter, frag, list); + + if (cursor != NULL && !fragment_index_insert(cursor, frag)) + return false; + + return true; +} + /* * !doc * @@ -585,26 +900,76 @@ pkgconf_fragment_has_system_dir(const pkgconf_client_t *client, const pkgconf_fr void pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_fragment_t *base, bool is_private) { - pkgconf_fragment_t *frag; + (void) pkgconf_fragment_copy_node(client, list, NULL, base, is_private); +} - if ((frag = pkgconf_fragment_exists(list, base, client->flags, is_private)) != NULL) - { - if (pkgconf_fragment_should_merge(frag)) - pkgconf_fragment_delete(list, frag); - } - else if (!is_private && !pkgconf_fragment_can_merge_back(base, client->flags, is_private) && (pkgconf_fragment_lookup(list, base) != NULL)) - return; +/* + * !doc + * + * .. c:function:: void pkgconf_fragment_cursor_init(pkgconf_fragment_cursor_t *cursor, pkgconf_list_t *list) + * + * Initialises a `fragment cursor` bound to a (typically empty) destination list. While the + * cursor is in use, fragments must be added to the list only via ``pkgconf_fragment_copy_cursor()`` + * so that the cursor's index stays in sync. + * + * :param pkgconf_fragment_cursor_t* cursor: The cursor to initialise. + * :param pkgconf_list_t* list: The destination fragment list. + * :return: nothing + */ +void +pkgconf_fragment_cursor_init(pkgconf_fragment_cursor_t *cursor, pkgconf_list_t *list) +{ + pkgconf_node_t *node; - frag = calloc(1, sizeof(pkgconf_fragment_t)); - if (frag == NULL) - return; + cursor->list = list; + cursor->index = NULL; + cursor->count = 0; + cursor->alloc = 0; - frag->type = base->type; - pkgconf_fragment_copy_list(client, &frag->children, &base->children); - if (base->data != NULL) - frag->data = strdup(base->data); + /* seed the index with anything already present, so dedup against pre-existing + * fragments behaves exactly as the linear scan would. */ + PKGCONF_FOREACH_LIST_ENTRY(list->head, node) + (void) fragment_index_insert(cursor, node->data); +} - pkgconf_node_insert_tail(&frag->iter, frag, list); +/* + * !doc + * + * .. c:function:: void pkgconf_fragment_cursor_deinit(pkgconf_fragment_cursor_t *cursor) + * + * Releases the index held by a `fragment cursor`. The destination list and its fragments are + * not affected. + * + * :param pkgconf_fragment_cursor_t* cursor: The cursor to release. + * :return: nothing + */ +void +pkgconf_fragment_cursor_deinit(pkgconf_fragment_cursor_t *cursor) +{ + free(cursor->index); + cursor->index = NULL; + cursor->count = 0; + cursor->alloc = 0; +} + +/* + * !doc + * + * .. c:function:: void pkgconf_fragment_copy_cursor(const pkgconf_client_t *client, pkgconf_fragment_cursor_t *cursor, const pkgconf_fragment_t *base, bool is_private) + * + * Like ``pkgconf_fragment_copy()``, but uses the cursor's sorted index for the mergeback lookup, + * turning what would be a linear scan of the destination list into a bsearch. + * + * :param pkgconf_client_t* client: The pkgconf client being accessed. + * :param pkgconf_fragment_cursor_t* cursor: The cursor bound to the destination list. + * :param pkgconf_fragment_t* base: The fragment being copied. + * :param bool is_private: Whether the fragment list is a `private` fragment list (static linking). + * :return: nothing + */ +void +pkgconf_fragment_copy_cursor(const pkgconf_client_t *client, pkgconf_fragment_cursor_t *cursor, const pkgconf_fragment_t *base, bool is_private) +{ + (void) pkgconf_fragment_copy_node(client, cursor->list, cursor, base, is_private); } /* @@ -623,14 +988,7 @@ pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, cons void pkgconf_fragment_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base) { - pkgconf_node_t *node; - - PKGCONF_FOREACH_LIST_ENTRY(base->head, node) - { - pkgconf_fragment_t *frag = node->data; - - pkgconf_fragment_copy(client, list, frag, true); - } + (void) pkgconf_fragment_copy_list_node(client, list, base); } /* @@ -657,7 +1015,47 @@ pkgconf_fragment_filter(const pkgconf_client_t *client, pkgconf_list_t *dest, pk pkgconf_fragment_t *frag = node->data; if (filter_func(client, frag, data)) - pkgconf_fragment_copy(client, dest, frag, true); + (void) pkgconf_fragment_copy_node(client, dest, NULL, frag, true); + } +} + +/* + * !doc + * + * .. c:function:: void pkgconf_fragment_filter_splice(const pkgconf_client_t *client, pkgconf_list_t *dest, pkgconf_list_t *src, pkgconf_fragment_filter_func_t filter_func, void *data) + * + * Like ``pkgconf_fragment_filter()``, but moves the matching `fragments` to `dest` instead of + * copying them. Fragments which do not match are left in `src` for the caller to release. + * + * :param pkgconf_client_t* client: The pkgconf client being accessed. + * :param pkgconf_list_t* dest: The destination list. + * :param pkgconf_list_t* src: The source list. + * :param pkgconf_fragment_filter_func_t filter_func: The filter function to use. + * :param void* data: Optional data to pass to the filter function. + * :return: nothing + */ +void +pkgconf_fragment_filter_splice(const pkgconf_client_t *client, pkgconf_list_t *dest, pkgconf_list_t *src, pkgconf_fragment_filter_func_t filter_func, void *data) +{ + pkgconf_node_t *node, *next; + + if (dest == src) + return; + + PKGCONF_FOREACH_LIST_ENTRY_SAFE(src->head, next, node) + { + pkgconf_fragment_t *frag = node->data; + + if (!filter_func(client, frag, data)) + continue; + + pkgconf_node_delete(node, src); + + /* pkgconf_node_delete() leaves the node's links pointing into the + * source list, and pkgconf_node_insert_tail() only overwrites prev. */ + node->prev = node->next = NULL; + + pkgconf_node_insert_tail(node, frag, dest); } } @@ -713,68 +1111,89 @@ pkgconf_is_locale_utf8(void) #endif } -static void +static const pkgconf_span_t quote_spans[] = { + { 0x00, 0x1f }, + { (unsigned char)' ', (unsigned char)'#' }, + { (unsigned char)'%', (unsigned char)'\'' }, + { (unsigned char)'*', (unsigned char)'*' }, + { (unsigned char)';', (unsigned char)'<' }, + { (unsigned char)'>', (unsigned char)'?' }, + { (unsigned char)'[', (unsigned char)']' }, + { (unsigned char)'`', (unsigned char)'`' }, + { (unsigned char)'{', (unsigned char)'}' }, + { 0x7f, 0xff }, +}; + +/* If the locale is UTF-8 we must not split character over 0x7f because it would add "\" between each bytes. + So only DEL (0x7f) needs escaping */ +static const pkgconf_span_t quote_spans_utf8[] = { + { 0x00, 0x1f }, + { (unsigned char)' ', (unsigned char)'#' }, + { (unsigned char)'%', (unsigned char)'\'' }, + { (unsigned char)'*', (unsigned char)'*' }, + { (unsigned char)';', (unsigned char)'<' }, + { (unsigned char)'>', (unsigned char)'?' }, + { (unsigned char)'[', (unsigned char)']' }, + { (unsigned char)'`', (unsigned char)'`' }, + { (unsigned char)'{', (unsigned char)'}' }, + { 0x7f, 0x7f }, +}; + +/* + * The set of bytes needing a backslash is fixed for the life of the process + * (pkgconf_is_locale_utf8() is itself cached), so resolve the spans into a + * byte-set once instead of walking them for every byte of every fragment. + */ +static const pkgconf_charset_t * +fragment_quote_charset(void) +{ + static pkgconf_charset_t charset; + static bool have_charset = false; + + if (!have_charset) + { + if (pkgconf_is_locale_utf8()) + pkgconf_charset_from_spans(&charset, quote_spans_utf8, PKGCONF_ARRAY_SIZE(quote_spans_utf8)); + else + pkgconf_charset_from_spans(&charset, quote_spans, PKGCONF_ARRAY_SIZE(quote_spans)); + + have_charset = true; + } + + return &charset; +} + +static bool fragment_quote(pkgconf_buffer_t *out, const pkgconf_fragment_t *frag) { if (frag->data == NULL) - return; + return true; - const pkgconf_buffer_t *src = PKGCONF_BUFFER_FROM_STR(frag->data); - const pkgconf_span_t quote_spans[] = { - { 0x00, 0x1f }, - { (unsigned char)' ', (unsigned char)'#' }, - { (unsigned char)'%', (unsigned char)'\'' }, - { (unsigned char)'*', (unsigned char)'*' }, - { (unsigned char)';', (unsigned char)'<' }, - { (unsigned char)'>', (unsigned char)'?' }, - { (unsigned char)'[', (unsigned char)']' }, - { (unsigned char)'`', (unsigned char)'`' }, - { (unsigned char)'{', (unsigned char)'}' }, - { 0x7f, 0xff }, - }; - - /* If the local is UTF-8 we must not split character over 0x7f because it would add "\" between each bytes. - So only DEL (0x7f) needs escaping */ - const pkgconf_span_t quote_spans_utf8[] = { - { 0x00, 0x1f }, - { (unsigned char)' ', (unsigned char)'#' }, - { (unsigned char)'%', (unsigned char)'\'' }, - { (unsigned char)'*', (unsigned char)'*' }, - { (unsigned char)';', (unsigned char)'<' }, - { (unsigned char)'>', (unsigned char)'?' }, - { (unsigned char)'[', (unsigned char)']' }, - { (unsigned char)'`', (unsigned char)'`' }, - { (unsigned char)'{', (unsigned char)'}' }, - { 0x7f, 0x7f }, - }; - - if (pkgconf_is_locale_utf8()) - pkgconf_buffer_escape(out, src, quote_spans_utf8, PKGCONF_ARRAY_SIZE(quote_spans_utf8)); - else - pkgconf_buffer_escape(out, src, quote_spans, PKGCONF_ARRAY_SIZE(quote_spans)); + return pkgconf_buffer_escape_charset(out, PKGCONF_BUFFER_FROM_STR(frag->data), fragment_quote_charset()); } -static void +static bool fragment_render(const pkgconf_fragment_render_ctx_t *ctx, const pkgconf_fragment_t *frag, pkgconf_buffer_t *buf) { const pkgconf_node_t *iter; - pkgconf_buffer_t quoted = PKGCONF_BUFFER_INITIALIZER; - fragment_quote("ed, frag); + if (frag->type && + (!pkgconf_buffer_push_byte(buf, '-') || !pkgconf_buffer_push_byte(buf, frag->type))) + return false; - if (frag->type) - pkgconf_buffer_append_fmt(buf, "-%c", frag->type); - - pkgconf_buffer_append(buf, pkgconf_buffer_str_or_empty("ed)); - pkgconf_buffer_finalize("ed); + if (!fragment_quote(buf, frag)) + return false; PKGCONF_FOREACH_LIST_ENTRY(frag->children.head, iter) { const pkgconf_fragment_t *child_frag = iter->data; - pkgconf_buffer_push_byte(buf, ctx->delim); - fragment_render(ctx, child_frag, buf); + if (!pkgconf_buffer_push_byte(buf, ctx->delim) || + !fragment_render(ctx, child_frag, buf)) + return false; } + + return true; } static const pkgconf_fragment_render_ops_t default_render_ops = { @@ -795,7 +1214,7 @@ static const pkgconf_fragment_render_ops_t default_render_ops = { * :param char delim: The delimiter to use between fragments. * :return: nothing */ -void +bool pkgconf_fragment_render_buf(const pkgconf_list_t *list, pkgconf_buffer_t *buf, bool escape, const pkgconf_fragment_render_ops_t *ops, char delim) { pkgconf_node_t *node; @@ -809,11 +1228,14 @@ pkgconf_fragment_render_buf(const pkgconf_list_t *list, pkgconf_buffer_t *buf, b PKGCONF_FOREACH_LIST_ENTRY(list->head, node) { const pkgconf_fragment_t *frag = node->data; - ops->render(&ctx, frag, buf); + if (!ops->render(&ctx, frag, buf)) + return false; - if (node->next != NULL) - pkgconf_buffer_push_byte(buf, ctx.delim); + if (node->next != NULL && !pkgconf_buffer_push_byte(buf, ctx.delim)) + return false; } + + return true; } /* @@ -832,7 +1254,7 @@ pkgconf_fragment_delete(pkgconf_list_t *list, pkgconf_fragment_t *node) { pkgconf_node_delete(&node->iter, list); - free(node->data); + pkgconf_fragment_free(&node->children); free(node); } @@ -856,9 +1278,10 @@ pkgconf_fragment_free(pkgconf_list_t *list) pkgconf_fragment_t *frag = node->data; pkgconf_fragment_free(&frag->children); - free(frag->data); free(frag); } + + pkgconf_list_zero(list); } /* @@ -878,46 +1301,5 @@ pkgconf_fragment_free(pkgconf_list_t *list) bool pkgconf_fragment_parse(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value, unsigned int flags) { - int i, ret, argc; - char **argv; - - ret = pkgconf_argv_split(value, &argc, &argv); - if (ret < 0) - { - PKGCONF_TRACE(client, "unable to parse fragment string [%s]", value); - return false; - } - - for (i = 0; i < argc; i++) - { - if (argv[i] == NULL) - { - PKGCONF_TRACE(client, "parsed fragment string is inconsistent: argc = %d while argv[%d] == NULL", argc, i); - pkgconf_argv_free(argv); - return false; - } - - bool greedy = pkgconf_fragment_is_greedy(argv[i]); - - PKGCONF_TRACE(client, "processing [%s] greedy=%d", argv[i], greedy); - - if (greedy && i + 1 < argc) - { - pkgconf_buffer_t greedybuf = PKGCONF_BUFFER_INITIALIZER; - - pkgconf_buffer_append(&greedybuf, argv[i]); - pkgconf_buffer_append(&greedybuf, argv[i + 1]); - pkgconf_fragment_add(client, list, vars, pkgconf_buffer_str(&greedybuf), flags); - pkgconf_buffer_finalize(&greedybuf); - - /* skip over next arg as we combined them */ - i++; - } - else - pkgconf_fragment_add(client, list, vars, argv[i], flags); - } - - pkgconf_argv_free(argv); - - return true; + return fragment_split(client, list, vars, value, flags, true); } diff --git a/contrib/pkgconf/libpkgconf/iter.h b/contrib/pkgconf/libpkgconf/iter.h index af2ec139bfcd..4c3a4dfb8b06 100644 --- a/contrib/pkgconf/libpkgconf/iter.h +++ b/contrib/pkgconf/libpkgconf/iter.h @@ -46,6 +46,26 @@ pkgconf_list_zero(pkgconf_list_t *list) list->length = 0; } +static inline void +pkgconf_list_splice(pkgconf_list_t *dest, pkgconf_list_t *src) +{ + if (dest == src || src->head == NULL) + return; + + if (dest->head == NULL) + dest->head = src->head; + else + { + dest->tail->next = src->head; + src->head->prev = dest->tail; + } + + dest->tail = src->tail; + dest->length += src->length; + + pkgconf_list_zero(src); +} + static inline void pkgconf_node_insert(pkgconf_node_t *node, void *data, pkgconf_list_t *list) { diff --git a/contrib/pkgconf/libpkgconf/libpkgconf-api.h b/contrib/pkgconf/libpkgconf/libpkgconf-api.h index a924c80ce833..123265e51ad4 100644 --- a/contrib/pkgconf/libpkgconf/libpkgconf-api.h +++ b/contrib/pkgconf/libpkgconf/libpkgconf-api.h @@ -12,6 +12,12 @@ # else # define PKGCONF_API __declspec(dllimport) # endif +#elif defined(__OS2__) +# if defined(LIBPKGCONF_EXPORT) || defined(DLL_EXPORT) +# define PKGCONF_API __declspec(dllexport) +# else +# define PKGCONF_API +# endif #else # define PKGCONF_API __attribute__((visibility("default"))) #endif diff --git a/contrib/pkgconf/libpkgconf/libpkgconf.h b/contrib/pkgconf/libpkgconf/libpkgconf.h index de646a2a54c5..80739705900c 100644 --- a/contrib/pkgconf/libpkgconf/libpkgconf.h +++ b/contrib/pkgconf/libpkgconf/libpkgconf.h @@ -71,8 +71,8 @@ typedef struct pkgconf_license_ pkgconf_license_t; #define PKGCONF_FOREACH_LIST_ENTRY_REVERSE(tail, value) \ for ((value) = (tail); (value) != NULL; (value) = (value)->prev) -#define LIBPKGCONF_VERSION 20993 -#define LIBPKGCONF_VERSION_STR "2.9.93" +#define LIBPKGCONF_VERSION 30009 +#define LIBPKGCONF_VERSION_STR "3.0.9" struct pkgconf_queue_ { pkgconf_node_t iter; @@ -256,12 +256,26 @@ struct pkgconf_pkg_ { }; typedef bool (*pkgconf_pkg_iteration_func_t)(const pkgconf_pkg_t *pkg, void *data); -typedef void (*pkgconf_pkg_traverse_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data); + +/* iteration state threaded through pkgconf_pkg_traverse() to its callback */ +#define PKGCONF_PKG_ITERF_NONE 0x0 +#define PKGCONF_PKG_ITERF_PRIVATE 0x1 + +typedef void (*pkgconf_pkg_traverse_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags); typedef bool (*pkgconf_queue_apply_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *world, void *data, int maxdepth); typedef bool (*pkgconf_error_handler_func_t)(const char *msg, const pkgconf_client_t *client, void *data); typedef void (*pkgconf_unveil_handler_func_t)(const pkgconf_client_t *client, const char *path, const char *permissions); typedef const char *(*pkgconf_environ_lookup_handler_func_t)(const pkgconf_client_t *client, const char *variable); +typedef struct pkgconf_client_options_ { + pkgconf_error_handler_func_t error_handler; + void *error_handler_data; + const pkgconf_cross_personality_t *personality; + void *client_data; + pkgconf_environ_lookup_handler_func_t environ_lookup_handler; + pkgconf_unveil_handler_func_t unveil_handler; +} pkgconf_client_options_t; + struct pkgconf_client_ { pkgconf_list_t dir_list; @@ -362,10 +376,13 @@ PKGCONF_API void pkgconf_variable_delete(pkgconf_list_t *vars, pkgconf_variable_ PKGCONF_API void pkgconf_variable_list_free(pkgconf_list_t *vars); PKGCONF_API bool pkgconf_variable_eval(pkgconf_client_t *client, const pkgconf_list_t *tuples, const pkgconf_variable_t *v, pkgconf_buffer_t *out, bool *saw_sysroot); PKGCONF_API char *pkgconf_variable_eval_str(pkgconf_client_t *client, const pkgconf_list_t *tuples, const pkgconf_variable_t *v, bool *saw_sysroot); +PKGCONF_API char *pkgconf_variable_eval_name(pkgconf_client_t *client, const pkgconf_list_t *vars, const char *varname); /* client.c */ PKGCONF_API void pkgconf_client_init(pkgconf_client_t *client, pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler); +PKGCONF_API void pkgconf_client_init_with_options(pkgconf_client_t *client, const pkgconf_client_options_t *options); PKGCONF_API pkgconf_client_t * pkgconf_client_new(pkgconf_error_handler_func_t error_handler, void *error_handler_data, const pkgconf_cross_personality_t *personality, void *client_data, pkgconf_environ_lookup_handler_func_t environ_lookup_handler); +PKGCONF_API pkgconf_client_t * pkgconf_client_new_with_options(const pkgconf_client_options_t *options); PKGCONF_API void pkgconf_client_deinit(pkgconf_client_t *client); PKGCONF_API void pkgconf_client_free(pkgconf_client_t *client); PKGCONF_API const char *pkgconf_client_get_sysroot_dir(const pkgconf_client_t *client); @@ -408,7 +425,7 @@ PKGCONF_API void pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *p #define PKGCONF_PKG_PKGF_SKIP_CONFLICTS 0x0020 #define PKGCONF_PKG_PKGF_NO_CACHE 0x0040 #define PKGCONF_PKG_PKGF_SKIP_ERRORS 0x0080 -#define PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE 0x0100 +/* 0x0100 reserved (was PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE; now threaded as a traversal parameter) */ #define PKGCONF_PKG_PKGF_SKIP_PROVIDES 0x0200 #define PKGCONF_PKG_PKGF_REDEFINE_PREFIX 0x0400 #define PKGCONF_PKG_PKGF_DONT_RELOCATE_PATHS 0x0800 @@ -418,6 +435,7 @@ PKGCONF_API void pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *p #define PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES 0x8000 #define PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES 0x10000 #define PKGCONF_PKG_PKGF_REQUIRE_INTERNAL 0x20000 +#define PKGCONF_PKG_PKGF_NO_SYSROOT_INJECTION 0x40000 #define PKGCONF_PKG_DEPF_INTERNAL 0x1 #define PKGCONF_PKG_DEPF_PRIVATE 0x2 @@ -457,11 +475,15 @@ PKGCONF_API bool pkgconf_default_error_handler(const char *msg, const pkgconf_cl #ifndef PKGCONF_LITE #if defined(__GNUC__) || defined(__INTEL_COMPILER) #define PKGCONF_TRACE(client, ...) do { \ - pkgconf_trace(client, __FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__); \ + const pkgconf_client_t *pkgconf_trace_client_ = (client); \ + if (pkgconf_trace_client_ != NULL && pkgconf_trace_client_->trace_handler != NULL) \ + pkgconf_trace(pkgconf_trace_client_, __FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__); \ } while (0) #else #define PKGCONF_TRACE(client, ...) do { \ - pkgconf_trace(client, __FILE__, __LINE__, __func__, __VA_ARGS__); \ + const pkgconf_client_t *pkgconf_trace_client_ = (client); \ + if (pkgconf_trace_client_ != NULL && pkgconf_trace_client_->trace_handler != NULL) \ + pkgconf_trace(pkgconf_trace_client_, __FILE__, __LINE__, __func__, __VA_ARGS__); \ } while (0) #endif #else @@ -499,6 +521,7 @@ PKGCONF_API pkgconf_dependency_t *pkgconf_dependency_copy(pkgconf_client_t *clie /* argvsplit.c */ PKGCONF_API int pkgconf_argv_split(const char *src, int *argc, char ***argv); +PKGCONF_API int pkgconf_argv_split_raw(const char *src, int *argc, char ***argv); PKGCONF_API void pkgconf_argv_free(char **argv); /* fragment.c */ @@ -508,29 +531,46 @@ typedef struct pkgconf_fragment_render_ctx_ { } pkgconf_fragment_render_ctx_t; typedef struct pkgconf_fragment_render_ops_ { - void (*render)(const pkgconf_fragment_render_ctx_t *ctx, const pkgconf_fragment_t *frag, pkgconf_buffer_t *buf); + bool (*render)(const pkgconf_fragment_render_ctx_t *ctx, const pkgconf_fragment_t *frag, pkgconf_buffer_t *buf); } pkgconf_fragment_render_ops_t; typedef bool (*pkgconf_fragment_filter_func_t)(const pkgconf_client_t *client, const pkgconf_fragment_t *frag, void *data); + +/* A cursor accelerates repeated pkgconf_fragment_copy() calls into the same + * destination list by maintaining a sorted index of the fragments already + * present, so that the deduplication lookup is a bsearch() rather than a linear + * scan of the (potentially large) accumulator. + */ +typedef struct pkgconf_fragment_cursor_ { + pkgconf_list_t *list; + pkgconf_fragment_t **index; + size_t count; + size_t alloc; +} pkgconf_fragment_cursor_t; + PKGCONF_API bool pkgconf_fragment_parse(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value, unsigned int flags); PKGCONF_API void pkgconf_fragment_insert(pkgconf_client_t *client, pkgconf_list_t *list, char type, const char *data, bool tail); -PKGCONF_API void pkgconf_fragment_add(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *string, unsigned int flags); +PKGCONF_API bool pkgconf_fragment_add(pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *string, unsigned int flags); PKGCONF_API void pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_fragment_t *base, bool is_private); +PKGCONF_API void pkgconf_fragment_cursor_init(pkgconf_fragment_cursor_t *cursor, pkgconf_list_t *list); +PKGCONF_API void pkgconf_fragment_cursor_deinit(pkgconf_fragment_cursor_t *cursor); +PKGCONF_API void pkgconf_fragment_copy_cursor(const pkgconf_client_t *client, pkgconf_fragment_cursor_t *cursor, const pkgconf_fragment_t *base, bool is_private); PKGCONF_API void pkgconf_fragment_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base); PKGCONF_API void pkgconf_fragment_delete(pkgconf_list_t *list, pkgconf_fragment_t *node); PKGCONF_API void pkgconf_fragment_free(pkgconf_list_t *list); PKGCONF_API void pkgconf_fragment_filter(const pkgconf_client_t *client, pkgconf_list_t *dest, pkgconf_list_t *src, pkgconf_fragment_filter_func_t filter_func, void *data); -PKGCONF_API void pkgconf_fragment_render_buf(const pkgconf_list_t *list, pkgconf_buffer_t *buf, bool escape, const pkgconf_fragment_render_ops_t *ops, char delim); +PKGCONF_API void pkgconf_fragment_filter_splice(const pkgconf_client_t *client, pkgconf_list_t *dest, pkgconf_list_t *src, pkgconf_fragment_filter_func_t filter_func, void *data); +PKGCONF_API bool pkgconf_fragment_render_buf(const pkgconf_list_t *list, pkgconf_buffer_t *buf, bool escape, const pkgconf_fragment_render_ops_t *ops, char delim); PKGCONF_API bool pkgconf_fragment_has_system_dir(const pkgconf_client_t *client, const pkgconf_fragment_t *frag); PKGCONF_API bool pkgconf_is_locale_utf8(void); /* license.c */ -PKGCONF_API void pkgconf_license_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base); -PKGCONF_API void pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *deplist_head, const char *expression, unsigned int flags); -PKGCONF_API void pkgconf_license_evaluate(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *deplist, const char *depends, unsigned int flags); +PKGCONF_API bool pkgconf_license_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base); +PKGCONF_API bool pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *deplist_head, const char *expression, unsigned int flags); +PKGCONF_API bool pkgconf_license_evaluate(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *deplist, const char *depends, unsigned int flags); PKGCONF_API void pkgconf_license_free(pkgconf_list_t *list); -PKGCONF_API void pkgconf_license_insert(pkgconf_client_t *client, pkgconf_list_t *list, unsigned char type, const char *data); -PKGCONF_API void pkgconf_license_render(pkgconf_client_t *client, const pkgconf_list_t *list, pkgconf_buffer_t *buf); +PKGCONF_API bool pkgconf_license_insert(pkgconf_client_t *client, pkgconf_list_t *list, unsigned char type, const char *data); +PKGCONF_API bool pkgconf_license_render(pkgconf_client_t *client, const pkgconf_list_t *list, pkgconf_buffer_t *buf); /* tuple.c */ PKGCONF_API pkgconf_tuple_t *pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *parent, const char *key, const char *value, bool parse, unsigned int flags); @@ -574,6 +614,7 @@ PKGCONF_API size_t pkgconf_path_build_from_registry(pkgconf_client_t *client, /* PKGCONF_API bool pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist); PKGCONF_API void pkgconf_path_free(pkgconf_list_t *dirlist); PKGCONF_API bool pkgconf_path_relocate(pkgconf_buffer_t *buf); +PKGCONF_API void pkgconf_path_normalize_separators(char *path); PKGCONF_API void pkgconf_path_copy_list(pkgconf_list_t *dst, const pkgconf_list_t *src); PKGCONF_API void pkgconf_path_prepend_list(pkgconf_list_t *dst, const pkgconf_list_t *src); PKGCONF_API bool pkgconf_path_is_plausible(const pkgconf_buffer_t *buf); @@ -592,6 +633,21 @@ static inline bool pkgconf_span_contains(unsigned char c, const pkgconf_span_t * return false; } +/* A set of byte values as a 256-bit map, so that membership is a single test + * rather than a walk over a span list. Build one with + * pkgconf_charset_from_spans() and keep it: the point is to hoist the span + * walk out of any per-byte loop. */ +typedef struct pkgconf_charset_ { + uint64_t words[4]; +} pkgconf_charset_t; + +static inline bool pkgconf_charset_contains(const pkgconf_charset_t *charset, unsigned char c) +{ + return (charset->words[c >> 6] >> (c & 63)) & 1; +} + +PKGCONF_API void pkgconf_charset_from_spans(pkgconf_charset_t *charset, const pkgconf_span_t *spans, size_t nspans); + PKGCONF_API bool pkgconf_buffer_append(pkgconf_buffer_t *buffer, const char *text); PKGCONF_API bool pkgconf_buffer_append_slice(pkgconf_buffer_t *buf, const char *p, size_t n); PKGCONF_API bool pkgconf_buffer_append_fmt(pkgconf_buffer_t *buffer, const char *fmt, ...) PRINTFLIKE(2, 3); @@ -609,6 +665,7 @@ PKGCONF_API bool pkgconf_buffer_contains_byte(const pkgconf_buffer_t *haystack, PKGCONF_API bool pkgconf_buffer_match(const pkgconf_buffer_t *haystack, const pkgconf_buffer_t *needle); PKGCONF_API bool pkgconf_buffer_subst(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const char *pattern, const char *value); PKGCONF_API bool pkgconf_buffer_escape(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_span_t *spans, size_t nspans); +PKGCONF_API bool pkgconf_buffer_escape_charset(pkgconf_buffer_t *dest, const pkgconf_buffer_t *src, const pkgconf_charset_t *charset); /* * !doc @@ -652,6 +709,9 @@ static inline const char *pkgconf_buffer_str_or_empty(const pkgconf_buffer_t *bu */ static inline size_t pkgconf_buffer_len(const pkgconf_buffer_t *buffer) { + if (buffer->base == NULL) + return 0; + return (size_t)(ptrdiff_t)(buffer->end - buffer->base); } @@ -693,24 +753,44 @@ static inline void pkgconf_buffer_reset(pkgconf_buffer_t *buffer) buffer->base = buffer->end = NULL; } +/* + * !doc + * + * .. c:function:: static inline void pkgconf_buffer_rewind(pkgconf_buffer_t *buffer) + * + * Truncate the buffer to empty while retaining its allocation, so it can be + * refilled without reallocating. Unlike pkgconf_buffer_reset(), the backing + * storage is kept. + * + * :param pkgconf_buffer_t *buffer: The buffer to rewind. + * :return: nothing + */ +static inline void pkgconf_buffer_rewind(pkgconf_buffer_t *buffer) +{ + if (buffer->base != NULL) + { + buffer->end = buffer->base; + *buffer->base = '\0'; + } +} + /* * !doc * * .. c:function:: static inline char *pkgconf_buffer_freeze(pkgconf_buffer_t *buffer) * - * Free the underlying buffer, copying the underlying string. - * The string must be freed by the caller. + * Hand ownership of the underlying storage to the caller as a string and + * empty the buffer. The string must be freed by the caller. * * :param pkgconf_buffer_t *buffer: The buffer to freeze. - * :return: The underlying string, copied. + * :return: The underlying string. */ static inline char *pkgconf_buffer_freeze(pkgconf_buffer_t *buffer) { - if (buffer->base == NULL) - return NULL; + char *out = buffer->base; + + buffer->base = buffer->end = NULL; - char *out = pkgconf_strndup(pkgconf_buffer_str(buffer), pkgconf_buffer_len(buffer)); - pkgconf_buffer_reset(buffer); return out; } @@ -720,6 +800,7 @@ static inline char *pkgconf_buffer_freeze(pkgconf_buffer_t *buffer) * .. c:function:: static inline bool pkgconf_buffer_copy(pkgconf_buffer_t *buffer, pkgconf_buffer_t *newptr) * * Copy the contents of one buffer to another, erasing the contents of the buffer in :code:`newptr`. + * The source and destination buffers must not overlap. * * :param pkgconf_buffer_t *buffer: The buffer to copy from. * :param pkgconf_buffer_t *buffer: The buffer to copy to. @@ -727,6 +808,9 @@ static inline char *pkgconf_buffer_freeze(pkgconf_buffer_t *buffer) */ static inline bool pkgconf_buffer_copy(pkgconf_buffer_t *buffer, pkgconf_buffer_t *newptr) { + if (buffer == newptr || (buffer->base != NULL && buffer->base == newptr->base)) + return false; + pkgconf_buffer_reset(newptr); return pkgconf_buffer_append_slice(newptr, pkgconf_buffer_str(buffer), pkgconf_buffer_len(buffer)); } diff --git a/contrib/pkgconf/libpkgconf/license.c b/contrib/pkgconf/libpkgconf/license.c index 7c7cb21802f0..7290ebd81179 100644 --- a/contrib/pkgconf/libpkgconf/license.c +++ b/contrib/pkgconf/libpkgconf/license.c @@ -18,7 +18,7 @@ #include #include -static void license_sanitize_string(const char *s, pkgconf_buffer_t *buf) +static bool license_sanitize_string(const char *s, pkgconf_buffer_t *buf) { unsigned int i = 0; /* @@ -31,24 +31,27 @@ static void license_sanitize_string(const char *s, pkgconf_buffer_t *buf) { if (isalnum((unsigned char) s[i]) || s[i] == '-' || s[i] == '+' || s[i] == '(' || s[i] == ')' || s[i] == '.' || s[i] == ':') { - pkgconf_buffer_push_byte(buf, s[i]); + if (!pkgconf_buffer_push_byte(buf, s[i])) + return false; } } + + return true; } /* * !doc * - * .. c:function:: void pkgconf_license_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base) + * .. c:function:: bool pkgconf_license_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base) * * Copies a `license list` to another `license list` * * :param pkgconf_client_t* client: The pkgconf client being accessed. * :param pkgconf_list_t* list: The list the fragments are being added to. * :param pkgconf_list_t* base: The list the fragments are being copied from. - * :return: nothing + * :return: true on success, false on allocation failure */ -void +bool pkgconf_license_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base) { pkgconf_node_t *node; @@ -60,17 +63,24 @@ pkgconf_license_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_license_t *cpy_license = calloc(1, sizeof(pkgconf_license_t)); if (cpy_license == NULL) - continue; + return false; cpy_license->type = license->type; if (license->data != NULL) { cpy_license->data = strdup(license->data); + if (cpy_license->data == NULL) + { + free(cpy_license); + return false; + } } pkgconf_node_insert_tail(&cpy_license->iter, cpy_license, list); } + + return true; } /* @@ -97,12 +107,14 @@ pkgconf_license_free(pkgconf_list_t *list) free(license->data); free(license); } + + pkgconf_list_zero(list); } /* * !doc * - * .. c:function:: void pkgconf_license_insert(pkgconf_client_t *client, pkgconf_list_t *list, unsigned char type, const char *data) + * .. c:function:: bool pkgconf_license_insert(pkgconf_client_t *client, pkgconf_list_t *list, unsigned char type, const char *data) * * Adds a `license` of text to a `license list` directly without interpreting it. * @@ -110,31 +122,39 @@ pkgconf_license_free(pkgconf_list_t *list) * :param pkgconf_list_t* list: The fragment list. * :param char type: The type of the license. * :param char* data: The data of the license - * :return: nothing + * :return: true on success, false on allocation failure */ -void +bool pkgconf_license_insert(pkgconf_client_t *client, pkgconf_list_t *list, unsigned char type, const char *data) { - (void) client; - pkgconf_license_t *license; + if (data == NULL) + return false; + license = calloc(1, sizeof(pkgconf_license_t)); if (!license) { pkgconf_error(client, "pkgconf_license_insert: out of memory"); - return; + return false; } license->type = type; license->data = strdup(data); + if (license->data == NULL) + { + pkgconf_error(client, "pkgconf_license_insert: out of memory"); + free(license); + return false; + } pkgconf_node_insert_tail(&license->iter, license, list); + return true; } /* * !doc * - * .. c:function:: pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *license_list, const char *expression, unsigned int flags) + * .. c:function:: bool pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *license_list, const char *expression, unsigned int flags) * * Evaluates SPDX expression strings like: * - BSD-3-Clause @@ -153,9 +173,9 @@ pkgconf_license_insert(pkgconf_client_t *client, pkgconf_list_t *list, unsigned * :param pkgconf_list_t* license_list: The dependency list to populate with dependency nodes. * :param char* expression: The dependency data to parse. * :param uint flags: Any flags to attach to the dependency nodes. - * :return: nothing + * :return: true on success, false on allocation failure */ -void +bool pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *license_list, const char *expression, unsigned int flags) { pkgconf_buffer_t out_buffer = PKGCONF_BUFFER_INITIALIZER; @@ -168,95 +188,112 @@ pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *license_l (void)flags; if (expression == NULL) - return; + return true; buf_size = strlen(expression) + 1; ret = pkgconf_argv_split(expression, &argc, &argv); - if (!ret) + if (ret) + return true; + + /* This is not the first License: + * so add AND + */ + if (license_list->head) { - /* This is not the first License: - * so add AND - */ - if (license_list->head) - { - pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_AND, "AND"); - } - - i = 0; - while (i < argc) - { - string_len = strnlen(argv[i], buf_size); - cur_word = argv[i]; - if (string_len >= 1) - { - license_sanitize_string(cur_word, &out_buffer); - if (!pkgconf_buffer_len(&out_buffer)) - { - i ++; - pkgconf_buffer_finalize(&out_buffer); - continue; - } - - cur_word = (char *)pkgconf_buffer_str(&out_buffer); - size_t cur_len = strnlen(cur_word, buf_size); - if (!cur_len) - { - i ++; - pkgconf_buffer_finalize(&out_buffer); - continue; - } - - if (cur_word[0] == '(') - { - pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_BRACKET_OPEN, "("); - /* If there is more after '(' like '(BSD-2-Clause' - * Then append rest to fragments as license. - * This is expression like GPL-2.0-only OR (BSD-2-Clause AND ISC) - */ - if (cur_len >= 2) - { - cur_word ++; - pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_EXPRESSION, cur_word); - } - } - else if (cur_word[cur_len - 1] == ')') - { - if (cur_len >= 2) - { - cur_word[cur_len - 1] = 0x00; - pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_EXPRESSION, cur_word); - } - pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_BRACKET_CLOSE, ")"); - } - else if (!strcasecmp(cur_word, "and")) - { - pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_AND, "AND"); - } - else if (!strcasecmp(cur_word, "or")) - { - pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_OR, "OR"); - } - else if (!strcasecmp(cur_word, "with")) - { - pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_WITH, "WITH"); - } - else - { - pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_EXPRESSION, cur_word); - } - pkgconf_buffer_finalize(&out_buffer); - } - i++; - } - - pkgconf_argv_free(argv); + if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_AND, "AND")) + goto fail; } + + i = 0; + while (i < argc) + { + string_len = strnlen(argv[i], buf_size); + cur_word = argv[i]; + if (string_len >= 1) + { + if (!license_sanitize_string(cur_word, &out_buffer)) + goto fail; + + if (!pkgconf_buffer_len(&out_buffer)) + { + i ++; + pkgconf_buffer_finalize(&out_buffer); + continue; + } + + cur_word = (char *)pkgconf_buffer_str(&out_buffer); + size_t cur_len = strnlen(cur_word, buf_size); + if (!cur_len) + { + i ++; + pkgconf_buffer_finalize(&out_buffer); + continue; + } + + if (cur_word[0] == '(') + { + if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_BRACKET_OPEN, "(")) + goto fail; + /* If there is more after '(' like '(BSD-2-Clause' + * Then append rest to fragments as license. + * This is expression like GPL-2.0-only OR (BSD-2-Clause AND ISC) + */ + if (cur_len >= 2) + { + cur_word ++; + if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_EXPRESSION, cur_word)) + goto fail; + } + } + else if (cur_word[cur_len - 1] == ')') + { + if (cur_len >= 2) + { + cur_word[cur_len - 1] = 0x00; + if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_EXPRESSION, cur_word)) + goto fail; + } + if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_BRACKET_CLOSE, ")")) + goto fail; + } + else if (!strcasecmp(cur_word, "and")) + { + if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_AND, "AND")) + goto fail; + } + else if (!strcasecmp(cur_word, "or")) + { + if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_OR, "OR")) + goto fail; + } + else if (!strcasecmp(cur_word, "with")) + { + if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_WITH, "WITH")) + goto fail; + } + else + { + if (!pkgconf_license_insert(client, license_list, PKGCONF_LICENSE_EXPRESSION, cur_word)) + goto fail; + } + pkgconf_buffer_finalize(&out_buffer); + } + i++; + } + + pkgconf_argv_free(argv); + return true; + +fail: + pkgconf_buffer_finalize(&out_buffer); + pkgconf_argv_free(argv); + return false; } /* * !doc * - * .. c:function:: pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *license_list, const char *expression, unsigned int flags) + * .. c:function:: bool pkgconf_license_evaluate(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *license_list, const char *license_str, unsigned int flags) * * Evaluates SPDX expression strings like: * - BSD-3-Clause @@ -275,15 +312,18 @@ pkgconf_license_evaluate_str(pkgconf_client_t *client, pkgconf_list_t *license_l * :param pkgconf_list_t* license_list: The dependency list to populate with dependency nodes. * :param char* expression: The dependency data to parse. * :param uint flags: Any flags to attach to the dependency nodes. - * :return: nothing + * :return: true on success, false on allocation failure */ -void +bool pkgconf_license_evaluate(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *license_list, const char *license_str, unsigned int flags) { char *license_expression = pkgconf_bytecode_eval_str(client, &pkg->vars, license_str, NULL); + if (license_expression == NULL) + return false; - pkgconf_license_evaluate_str(client, license_list, license_expression, flags); + bool ret = pkgconf_license_evaluate_str(client, license_list, license_expression, flags); free(license_expression); + return ret; } /* @@ -300,7 +340,7 @@ pkgconf_license_evaluate(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_l * :param uint flags: Any flags to attach to the dependency nodes. * :return: nothing */ -void +bool pkgconf_license_render(pkgconf_client_t *client, const pkgconf_list_t *list, pkgconf_buffer_t *buf) { const pkgconf_buffer_t *frag_string = NULL; @@ -314,7 +354,8 @@ pkgconf_license_render(pkgconf_client_t *client, const pkgconf_list_t *list, pkg pkgconf_license_t *license = node->data; is_delim = true; frag_string = PKGCONF_BUFFER_FROM_STR(license->data); - pkgconf_buffer_append(buf, pkgconf_buffer_str_or_empty(frag_string)); + if (!pkgconf_buffer_append(buf, pkgconf_buffer_str_or_empty(frag_string))) + return false; if (license->type == PKGCONF_LICENSE_BRACKET_OPEN || (node->next != NULL && ((const pkgconf_license_t *)node->next->data)->type == PKGCONF_LICENSE_BRACKET_CLOSE)) { @@ -323,7 +364,10 @@ pkgconf_license_render(pkgconf_client_t *client, const pkgconf_list_t *list, pkg if (node->next != NULL && is_delim) { - pkgconf_buffer_push_byte(buf, ' '); + if (!pkgconf_buffer_push_byte(buf, ' ')) + return false; } } + + return true; } diff --git a/contrib/pkgconf/libpkgconf/output.c b/contrib/pkgconf/libpkgconf/output.c index fc7ab85ea2e1..5c4a7437cc52 100644 --- a/contrib/pkgconf/libpkgconf/output.c +++ b/contrib/pkgconf/libpkgconf/output.c @@ -24,11 +24,15 @@ pkgconf_output_putbuf(pkgconf_output_t *output, pkgconf_output_stream_t stream, bool ret; pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; - if (pkgconf_buffer_len(buffer) != 0) - pkgconf_buffer_append(&buf, pkgconf_buffer_str(buffer)); + if (pkgconf_buffer_len(buffer) != 0 && + !pkgconf_buffer_append(&buf, pkgconf_buffer_str(buffer))) + return false; - if (newline) - pkgconf_buffer_push_byte(&buf, '\n'); + if (newline && !pkgconf_buffer_push_byte(&buf, '\n')) + { + pkgconf_buffer_finalize(&buf); + return false; + } ret = output->write(output, stream, &buf); pkgconf_buffer_finalize(&buf); @@ -42,8 +46,13 @@ pkgconf_output_puts(pkgconf_output_t *output, pkgconf_output_stream_t stream, co bool ret; pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; - pkgconf_buffer_append(&buf, str); - pkgconf_buffer_push_byte(&buf, '\n'); + if (!pkgconf_buffer_append(&buf, str) || + !pkgconf_buffer_push_byte(&buf, '\n')) + { + pkgconf_buffer_finalize(&buf); + return false; + } + ret = output->write(output, stream, &buf); pkgconf_buffer_finalize(&buf); @@ -71,10 +80,11 @@ pkgconf_output_vfmt(pkgconf_output_t *output, pkgconf_output_stream_t stream, co pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; va_copy(va, src_va); - pkgconf_buffer_append_vfmt(&buf, fmt, va); + ret = pkgconf_buffer_append_vfmt(&buf, fmt, va); va_end(va); - ret = output->write(output, stream, &buf); + if (ret) + ret = output->write(output, stream, &buf); pkgconf_buffer_finalize(&buf); return ret; diff --git a/contrib/pkgconf/libpkgconf/parser.c b/contrib/pkgconf/libpkgconf/parser.c index 11f023267388..828ceb4fcd92 100644 --- a/contrib/pkgconf/libpkgconf/parser.c +++ b/contrib/pkgconf/libpkgconf/parser.c @@ -145,7 +145,7 @@ pkgconf_parser_parse(FILE *f, void *data, const pkgconf_parser_operand_func_t *o snprintf(warnprefix, sizeof warnprefix, "%s:" SIZE_FMT_SPECIFIER, filename, lineno); pkgconf_parser_parse_buffer(data, ops, warnfunc, &readbuf, warnprefix); - pkgconf_buffer_reset(&readbuf); + pkgconf_buffer_rewind(&readbuf); } pkgconf_buffer_finalize(&readbuf); diff --git a/contrib/pkgconf/libpkgconf/path.c b/contrib/pkgconf/libpkgconf/path.c index 11891c61799f..80db1658e450 100644 --- a/contrib/pkgconf/libpkgconf/path.c +++ b/contrib/pkgconf/libpkgconf/path.c @@ -67,8 +67,14 @@ prepare_path_node(const char *text, pkgconf_list_t *dirlist, bool filter) pkgconf_path_t *node; pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER; - pkgconf_buffer_append(&pathbuf, text); - pkgconf_path_relocate(&pathbuf); + if (!pkgconf_buffer_append(&pathbuf, text)) + return NULL; + + if (!pkgconf_path_relocate(&pathbuf)) + { + pkgconf_buffer_finalize(&pathbuf); + return NULL; + } #ifdef PKGCONF_CACHE_INODES struct stat st; @@ -267,7 +273,9 @@ pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist) if (path == NULL) return false; - pkgconf_buffer_append(&relocated, path); + if (!pkgconf_buffer_append(&relocated, path)) + return false; + cpath = pkgconf_buffer_str(&relocated); if (pkgconf_path_relocate(&relocated)) @@ -400,32 +408,32 @@ pkgconf_path_free(pkgconf_list_t *dirlist) pkgconf_list_zero(dirlist); } -static char * -normpath(const pkgconf_buffer_t *pathbuf) +/* + * !doc + * + * .. c:function:: void pkgconf_path_normalize_separators(char *path) + * + * Rewrites a real OS path into pkgconf's canonical internal form, in which + * the platform directory separator is always represented as ``/``. On POSIX + * this is a no-op (a backslash is an ordinary filename character); on Windows + * it maps ``\`` to ``/``. Runtime-injected paths (search paths, sysroot, + * build root, prefix, pcfiledir) are normalized this way so that later path + * comparisons -- sysroot injection and system-directory filtering -- are all + * made on a consistent basis. + * + * :param char* path: The path to normalize in place. + * :return: nothing + */ +void +pkgconf_path_normalize_separators(char *path) { - if (!pathbuf || pkgconf_buffer_len(pathbuf) == 0) - return NULL; - - const char *path = pkgconf_buffer_str(pathbuf); - char *copy = strdup(path); - if (NULL == copy) - return NULL; - char *ptr = copy; - - for (int ii = 0; copy[ii]; ii++) - { - *ptr++ = path[ii]; - if ('/' == path[ii]) - { - ii++; - while ('/' == path[ii]) - ii++; - ii--; - } - } - *ptr = '\0'; - - return copy; +#ifdef _WIN32 + for (; *path != '\0'; path++) + if (*path == PKG_DIR_SEP_S) + *path = '/'; +#else + (void) path; +#endif } /* @@ -433,7 +441,8 @@ normpath(const pkgconf_buffer_t *pathbuf) * * .. c:function:: bool pkgconf_path_relocate(pkgconf_buffer_t *buf) * - * Relocates a path, possibly calling normpath() on it. + * Normalizes a path in place: folds the platform separator to '/' and + * collapses runs of '/'. * * :param pkgconf_buffer_t* buf: The path to relocate. * :return: true on success, false on error @@ -442,15 +451,30 @@ normpath(const pkgconf_buffer_t *pathbuf) bool pkgconf_path_relocate(pkgconf_buffer_t *buf) { - char *tmpbuf; + char *base = buf->base; + char *w; + const char *r; - if ((tmpbuf = normpath(buf)) != NULL) + if (base == NULL || pkgconf_buffer_len(buf) == 0) + return true; + + /* fold the platform separator to '/' before collapsing runs, so that a + * mix of '\' and '/' (as seen on Windows) is treated uniformly. */ + pkgconf_path_normalize_separators(base); + + /* collapse runs of '/' in place; the result never grows, so w <= r always */ + w = base; + for (r = base; *r != '\0'; r++) { - pkgconf_buffer_reset(buf); - pkgconf_buffer_append(buf, tmpbuf); - free(tmpbuf); + *w++ = *r; + if (*r == '/') + while (r[1] == '/') + r++; } + *w = '\0'; + buf->end = w; + return true; } @@ -474,7 +498,7 @@ pkgconf_path_trim_basename(pkgconf_buffer_t *buf) return false; sep = strrchr(buf->base, PKG_DIR_SEP_S); -#ifdef _WIN32 +#if defined(_WIN32) || defined(__OS2__) char *sep2 = strrchr(buf->base, '/'); if (sep2 != NULL && (sep == NULL || sep2 > sep)) sep = sep2; @@ -507,7 +531,7 @@ pkgconf_path_find_basename(const char *path) const char *sep; sep = strrchr(path, PKG_DIR_SEP_S); -#ifdef _WIN32 +#if defined(_WIN32) || defined(__OS2__) const char *sep2 = strrchr(path, '/'); if (sep2 != NULL && (sep == NULL || sep2 > sep)) sep = sep2; diff --git a/contrib/pkgconf/libpkgconf/personality.c b/contrib/pkgconf/libpkgconf/personality.c index 076337695893..672b4893654f 100644 --- a/contrib/pkgconf/libpkgconf/personality.c +++ b/contrib/pkgconf/libpkgconf/personality.c @@ -59,11 +59,9 @@ build_default_search_path(pkgconf_list_t* dirlist) * https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamea */ int sizepath = GetModuleFileName(NULL, namebuf, sizeof namebuf - 1); - char * winslash; namebuf[sizepath] = '\0'; - while ((winslash = strchr(namebuf, '\\')) != NULL) - *winslash = '/'; + pkgconf_path_normalize_separators(namebuf); p = strrchr(namebuf, '/'); if (p == NULL) @@ -75,7 +73,7 @@ build_default_search_path(pkgconf_list_t* dirlist) pkgconf_buffer_append_fmt(&pathbuf, "%s/../lib/pkgconfig", namebuf); pkgconf_path_add(pkgconf_buffer_str(&pathbuf), dirlist, true); - pkgconf_buffer_reset(&pathbuf); + pkgconf_buffer_rewind(&pathbuf); pkgconf_buffer_append_fmt(&pathbuf, "%s/../share/pkgconfig", namebuf); pkgconf_path_add(pkgconf_buffer_str(&pathbuf), dirlist, true); @@ -309,11 +307,20 @@ load_personality_with_path(const char *path, const char *triplet, bool datadir) /* if triplet is null, assume that path is a direct path to the personality file */ if (triplet == NULL) - pkgconf_buffer_append(&pathbuf, path); + { + if (!pkgconf_buffer_append(&pathbuf, path)) + return NULL; + } else if (datadir) - pkgconf_buffer_append_fmt(&pathbuf, "%s/pkgconfig/personality.d/%s.personality", path, triplet); + { + if (!pkgconf_buffer_append_fmt(&pathbuf, "%s/pkgconfig/personality.d/%s.personality", path, triplet)) + return NULL; + } else - pkgconf_buffer_append_fmt(&pathbuf, "%s/%s.personality", path, triplet); + { + if (!pkgconf_buffer_append_fmt(&pathbuf, "%s/%s.personality", path, triplet)) + return NULL; + } p = calloc(1, sizeof(pkgconf_cross_personality_t)); if (p == NULL) diff --git a/contrib/pkgconf/libpkgconf/pkg.c b/contrib/pkgconf/libpkgconf/pkg.c index 16e38e6e3783..67613e2f8877 100644 --- a/contrib/pkgconf/libpkgconf/pkg.c +++ b/contrib/pkgconf/libpkgconf/pkg.c @@ -38,7 +38,8 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client, pkgconf_pkg_traverse_func_t func, void *data, int maxdepth, - unsigned int skip_flags); + unsigned int skip_flags, + unsigned int iter_flags); static inline bool str_has_suffix(const char *str, const char *suffix) @@ -61,7 +62,8 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg) pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t pathbuf = PKGCONF_BUFFER_INITIALIZER; - pkgconf_buffer_append(&buf, pkg->filename); + if (!pkgconf_buffer_append(&buf, pkg->filename)) + goto fail; #ifndef _WIN32 struct stat path_stat; @@ -73,8 +75,9 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg) char sourcebuf[PKGCONF_ITEM_SIZE]; char *targetfilename, *targetdir; - pkgconf_buffer_reset(&pathbuf); - pkgconf_buffer_append(&pathbuf, buf.base); + pkgconf_buffer_rewind(&pathbuf); + if (!pkgconf_buffer_append(&pathbuf, buf.base)) + goto fail; targetfilename = strrchr(pathbuf.base, '/'); if (targetfilename != NULL) @@ -91,7 +94,7 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg) targetdir = "."; } -#ifdef HAVE_DECL_READLINKAT +#if HAVE_DECL_READLINKAT const int dirfd = open(targetdir, O_DIRECTORY); if (dirfd == -1) break; @@ -106,7 +109,7 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg) break; sourcebuf[len] = '\0'; - pkgconf_buffer_reset(&buf); + pkgconf_buffer_rewind(&buf); /* * The logic here can be a bit tricky, so here's a table: @@ -118,10 +121,18 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg) * /bar (absolute) | /foo/link (absolute) | /bar (absolute) * ../bar (relative) | /foo/link (absolute) | /foo/../bar (relative) */ - if ((sourcebuf[0] != '/') && strcmp(targetdir, ".")) - pkgconf_buffer_append_fmt(&buf, "%s/", targetdir); + if ((sourcebuf[0] != '/') && +#ifdef __OS2__ + !(sourcebuf[0] != '\0' && sourcebuf[1] == ':') && +#endif + strcmp(targetdir, ".")) + { + if (!pkgconf_buffer_append(&buf, targetdir) || !pkgconf_buffer_push_byte(&buf, '/')) + goto fail; + } - pkgconf_buffer_append(&buf, sourcebuf); + if (!pkgconf_buffer_append(&buf, sourcebuf)) + goto fail; } #endif @@ -131,6 +142,11 @@ pkg_get_parent_dir(pkgconf_pkg_t *pkg) pkgconf_path_trim_basename(&buf); return pkgconf_buffer_freeze(&buf); + +fail: + pkgconf_buffer_finalize(&pathbuf); + pkgconf_buffer_finalize(&buf); + return NULL; } typedef void (*pkgconf_pkg_parser_keyword_func_t)(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value); @@ -169,8 +185,9 @@ pkgconf_pkg_parser_bufferset_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; - pkgconf_bytecode_eval_str_to_buf(client, &pkg->vars, value, NULL, &buf); - pkgconf_bufferset_extend(dest, &buf); + if (pkgconf_bytecode_eval_str_to_buf(client, &pkg->vars, value, NULL, &buf)) + pkgconf_bufferset_extend(dest, &buf); + pkgconf_buffer_finalize(&buf); } @@ -195,7 +212,14 @@ pkgconf_pkg_parser_link_abi_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, c p++; while (*p != '\0' && *p != ',' && !isspace((unsigned char) *p)) - pkgconf_buffer_push_byte(&tag, (char) tolower((unsigned char) *p++)); + { + if (!pkgconf_buffer_push_byte(&tag, (char) tolower((unsigned char) *p++))) + { + pkgconf_buffer_finalize(&tag); + free(expanded); + return; + } + } if (pkgconf_buffer_len(&tag)) pkgconf_bufferset_extend(dest, &tag); @@ -312,9 +336,10 @@ static void pkgconf_pkg_evaluate_license_func(pkgconf_client_t *client, pkgconf_pkg_t *pkg, const char *keyword, const char *warnprefix, const ptrdiff_t offset, const char *value) { pkgconf_list_t *dest = (pkgconf_list_t *)((char *) pkg + offset); - (void)keyword; - (void)warnprefix; - pkgconf_license_evaluate(client, pkg, dest, value, 0); + + if (!pkgconf_license_evaluate(client, pkg, dest, value, 0)) + pkgconf_warn(client, "%s: warning: license field '%s' could not be fully evaluated\n", + warnprefix, keyword); } /* keep this in alphabetical order */ @@ -361,7 +386,9 @@ pkgconf_pkg_parser_keyword_set(void *opaque, const char *warnprefix, const char static bool determine_prefix(const pkgconf_pkg_t *pkg, pkgconf_buffer_t *pathbuf) { - pkgconf_buffer_append(pathbuf, pkg->filename); + if (!pkgconf_buffer_append(pathbuf, pkg->filename)) + return false; + pkgconf_path_relocate(pathbuf); pkgconf_path_trim_basename(pathbuf); @@ -396,18 +423,28 @@ convert_path_to_value(const char *path) for (i = path; *i != '\0'; i++) { - if (*i == PKG_DIR_SEP_S) - pkgconf_buffer_push_byte(&buf, '/'); - else if (*i == ' ') + char c = *i; + +#ifdef _WIN32 + if (c == PKG_DIR_SEP_S) + c = '/'; +#endif + + if (c == ' ') { - pkgconf_buffer_push_byte(&buf, '\\'); - pkgconf_buffer_push_byte(&buf, ' '); + if (!pkgconf_buffer_push_byte(&buf, '\\') || + !pkgconf_buffer_push_byte(&buf, ' ')) + goto fail; } - else - pkgconf_buffer_push_byte(&buf, *i); + else if (!pkgconf_buffer_push_byte(&buf, c)) + goto fail; } return pkgconf_buffer_freeze(&buf); + +fail: + pkgconf_buffer_finalize(&buf); + return NULL; } static void @@ -440,22 +477,37 @@ canonicalize_path(char *buf) static bool is_path_prefix_equal(const char *path1, const char *path2, size_t path2_len) { -#ifdef _WIN32 - return !_strnicmp(path1, path2, path2_len); +#if defined(_WIN32) || defined(__OS2__) + return !strncasecmp(path1, path2, path2_len); #else return !strncmp(path1, path2, path2_len); #endif } +static inline bool +is_path_separator(char c) +{ +#ifdef _WIN32 + return c == '/' || c == '\\'; +#else + return c == '/'; +#endif +} + static inline const char * lookup_val_from_env(const pkgconf_client_t *client, const char *pkg_id, const char *keyword) { - char env_var[PKGCONF_ITEM_SIZE]; + pkgconf_buffer_t env_var = PKGCONF_BUFFER_INITIALIZER; + const char *result; char *c; - snprintf(env_var, sizeof env_var, "PKG_CONFIG_%s_%s", pkg_id, keyword); + if (!pkgconf_buffer_join(&env_var, '_', "PKG_CONFIG", pkg_id, keyword, NULL)) + { + pkgconf_buffer_finalize(&env_var); + return NULL; + } - for (c = env_var; *c; c++) + for (c = env_var.base; *c != '\0'; c++) { *c = (char) toupper((unsigned char) *c); @@ -463,7 +515,11 @@ lookup_val_from_env(const pkgconf_client_t *client, const char *pkg_id, const ch *c = '_'; } - return pkgconf_client_getenv(client, env_var); + result = pkgconf_client_getenv(client, pkgconf_buffer_str(&env_var)); + + pkgconf_buffer_finalize(&env_var); + + return result; } static void @@ -482,17 +538,17 @@ pkgconf_pkg_parser_value_set(void *opaque, const char *warnprefix, const char *k value = env_content; } + if (!(pkg->owner->flags & PKGCONF_PKG_PKGF_REDEFINE_PREFIX)) + { + pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true, pkg->flags); + return; + } + if (!pkgconf_buffer_append(&canonicalized_value, value)) goto out; canonicalize_path(canonicalized_value.base); - if (!(pkg->owner->flags & PKGCONF_PKG_PKGF_REDEFINE_PREFIX)) - { - pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, value, true, pkg->flags); - goto out; - } - /* Some pc files will use absolute paths for all of their directories * which is broken when redefining the prefix. We try to outsmart the * file and rewrite any directory that starts with the same prefix. @@ -502,14 +558,29 @@ pkgconf_pkg_parser_value_set(void *opaque, const char *warnprefix, const char *k if (pkgconf_buffer_len(&pkg->orig_prefix) != 0) { const char *op = pkgconf_buffer_str_or_empty(&pkg->orig_prefix); - const size_t oplen = pkgconf_buffer_len(&pkg->orig_prefix); + const char *cv = pkgconf_buffer_str(&canonicalized_value); + size_t oplen = pkgconf_buffer_len(&pkg->orig_prefix); - if (is_path_prefix_equal(pkgconf_buffer_str(&canonicalized_value), op, oplen)) + /* Match orig_prefix as a directory path: disregard any trailing + * separator so oplen describes the directory itself, and require + * the value to continue on a component boundary. This leaves the + * separator at cv[oplen] as the tail's leading character, which + * joins it to calculated_prefix (which never has a trailing one). + */ + while (oplen > 1 && is_path_separator(op[oplen - 1])) + oplen--; + + if (is_path_prefix_equal(cv, op, oplen) && + (cv[oplen] == '\0' || is_path_separator(cv[oplen]))) { pkgconf_buffer_t newvalue = PKGCONF_BUFFER_INITIALIZER; - pkgconf_buffer_append(&newvalue, pkgconf_buffer_str_or_empty(&pkg->calculated_prefix)); - pkgconf_buffer_append(&newvalue, pkgconf_buffer_str(&canonicalized_value) + oplen); + if (!pkgconf_buffer_append(&newvalue, pkgconf_buffer_str_or_empty(&pkg->calculated_prefix)) || + !pkgconf_buffer_append(&newvalue, cv + oplen)) + { + pkgconf_buffer_finalize(&newvalue); + goto out; + } pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, pkgconf_buffer_str(&newvalue), false, pkg->flags); pkgconf_buffer_finalize(&newvalue); @@ -529,8 +600,14 @@ pkgconf_pkg_parser_value_set(void *opaque, const char *warnprefix, const char *k const char *relvalue = pkgconf_buffer_str(&pathbuf); char *prefix_value = convert_path_to_value(relvalue); - pkgconf_buffer_append(&pkg->orig_prefix, pkgconf_buffer_str(&canonicalized_value)); - pkgconf_buffer_append(&pkg->calculated_prefix, prefix_value); + if (prefix_value == NULL || + !pkgconf_buffer_append(&pkg->orig_prefix, pkgconf_buffer_str(&canonicalized_value)) || + !pkgconf_buffer_append(&pkg->calculated_prefix, prefix_value)) + { + free(prefix_value); + pkgconf_buffer_finalize(&pathbuf); + goto out; + } pkgconf_tuple_add(pkg->owner, &pkg->vars, keyword, prefix_value, false, pkg->flags); free(prefix_value); @@ -720,6 +797,10 @@ pkgconf_pkg_new_from_path(pkgconf_client_t *client, const char *filename, unsign return NULL; } + /* keep pc_filedir in canonical (forward-slash) form so it compares + * consistently against sysroot_dir and the search-path entries below */ + pkgconf_path_normalize_separators(pkg->pc_filedir); + char *pc_filedir_value = convert_path_to_value(pkg->pc_filedir); pkgconf_tuple_add(client, &pkg->vars, "pcfiledir", pc_filedir_value, true, pkg->flags); free(pc_filedir_value); @@ -770,7 +851,12 @@ pkgconf_pkg_new_from_path(pkgconf_client_t *client, const char *filename, unsign { pkgconf_buffer_t abibuf = PKGCONF_BUFFER_INITIALIZER; - pkgconf_buffer_append(&abibuf, "c"); + if (!pkgconf_buffer_append(&abibuf, "c")) + { + pkgconf_pkg_free(client, pkg); + return NULL; + } + pkgconf_bufferset_extend(&pkg->link_abi, &abibuf); pkgconf_buffer_finalize(&abibuf); } @@ -874,22 +960,35 @@ static inline pkgconf_pkg_t * pkgconf_pkg_try_specific_path(pkgconf_client_t *client, const char *path, const char *name) { pkgconf_pkg_t *pkg = NULL; - char locbuf[PKGCONF_ITEM_SIZE]; - char uninst_locbuf[PKGCONF_ITEM_SIZE]; + pkgconf_buffer_t locbuf = PKGCONF_BUFFER_INITIALIZER; PKGCONF_TRACE(client, "trying path: %s for %s", path, name); - snprintf(locbuf, sizeof locbuf, "%s%c%s" PKG_CONFIG_EXT, path, PKG_DIR_SEP_S, name); - snprintf(uninst_locbuf, sizeof uninst_locbuf, "%s%c%s-uninstalled" PKG_CONFIG_EXT, path, PKG_DIR_SEP_S, name); - if (!(client->flags & PKGCONF_PKG_PKGF_NO_UNINSTALLED)) - pkg = pkgconf_pkg_new_from_path(client, uninst_locbuf, PKGCONF_PKG_PROPF_UNINSTALLED); + { + pkgconf_buffer_append(&locbuf, path); + pkgconf_buffer_push_byte(&locbuf, PKG_DIR_SEP_S); + pkgconf_buffer_append(&locbuf, name); + pkgconf_buffer_append(&locbuf, "-uninstalled" PKG_CONFIG_EXT); + + pkg = pkgconf_pkg_new_from_path(client, pkgconf_buffer_str(&locbuf), PKGCONF_PKG_PROPF_UNINSTALLED); + } if (pkg == NULL) - pkg = pkgconf_pkg_new_from_path(client, locbuf, 0); + { + pkgconf_buffer_rewind(&locbuf); + pkgconf_buffer_append(&locbuf, path); + pkgconf_buffer_push_byte(&locbuf, PKG_DIR_SEP_S); + pkgconf_buffer_append(&locbuf, name); + pkgconf_buffer_append(&locbuf, PKG_CONFIG_EXT); + + pkg = pkgconf_pkg_new_from_path(client, pkgconf_buffer_str(&locbuf), 0); + } if (pkg != NULL) - PKGCONF_TRACE(client, "found%s: %s", pkg->flags & PKGCONF_PKG_PROPF_UNINSTALLED ? " (uninstalled)" : "", uninst_locbuf); + PKGCONF_TRACE(client, "found%s: %s", pkg->flags & PKGCONF_PKG_PROPF_UNINSTALLED ? " (uninstalled)" : "", pkgconf_buffer_str(&locbuf)); + + pkgconf_buffer_finalize(&locbuf); return pkg; } @@ -910,9 +1009,13 @@ pkgconf_pkg_scan_dir(pkgconf_client_t *client, const char *path, void *data, pkg for (dirent = readdir(dir); dirent != NULL; dirent = readdir(dir)) { pkgconf_buffer_t filebuf = PKGCONF_BUFFER_INITIALIZER; - pkgconf_pkg_t *pkg; + pkgconf_pkg_t *pkg = NULL; - pkgconf_buffer_join(&filebuf, '/', path, dirent->d_name, NULL); + if (!pkgconf_buffer_join(&filebuf, '/', path, dirent->d_name, NULL)) + { + closedir(dir); + return NULL; + } if (!str_has_suffix(pkgconf_buffer_str(&filebuf), PKG_CONFIG_EXT)) { @@ -920,13 +1023,34 @@ pkgconf_pkg_scan_dir(pkgconf_client_t *client, const char *path, void *data, pkg continue; } + if (!(client->flags & PKGCONF_PKG_PKGF_NO_CACHE)) + { + pkgconf_buffer_t idbuf = PKGCONF_BUFFER_INITIALIZER; + + if (pkgconf_buffer_append(&idbuf, pkgconf_path_find_basename(pkgconf_buffer_str(&filebuf)))) + { + char *idptr = strrchr(pkgconf_buffer_str(&idbuf), '.'); + + if (idptr != NULL) + *idptr = '\0'; + + pkg = pkgconf_cache_lookup(client, pkgconf_buffer_str(&idbuf)); + } + + pkgconf_buffer_finalize(&idbuf); + } + PKGCONF_TRACE(client, "trying file [%s]", pkgconf_buffer_str(&filebuf)); - pkg = pkgconf_pkg_new_from_path(client, pkgconf_buffer_str(&filebuf), 0); + if (pkg == NULL) + pkg = pkgconf_pkg_new_from_path(client, pkgconf_buffer_str(&filebuf), 0); pkgconf_buffer_finalize(&filebuf); if (pkg != NULL) { + if (!(pkg->flags & PKGCONF_PKG_PROPF_CACHED) && !(client->flags & PKGCONF_PKG_PKGF_NO_CACHE)) + pkgconf_cache_add(client, pkg); + if (func(pkg, data)) { outpkg = pkg; @@ -1523,7 +1647,8 @@ pkgconf_pkg_walk_list(pkgconf_client_t *client, pkgconf_pkg_traverse_func_t func, void *data, int depth, - unsigned int skip_flags) + unsigned int skip_flags, + unsigned int iter_flags) { unsigned int eflags = PKGCONF_PKG_ERRF_OK; pkgconf_node_t *node, *next; @@ -1555,7 +1680,7 @@ pkgconf_pkg_walk_list(pkgconf_client_t *client, if((pkgdep->flags & PKGCONF_PKG_PROPF_ANCESTOR) != 0) { /* In this case we have a circular reference. - * We break that by deleteing the circular node from the + * We break that by deleting the circular node from the * the list, so that we dont create a situation where * memory is leaked due to circular ownership. * i.e: A owns B owns A @@ -1582,7 +1707,7 @@ pkgconf_pkg_walk_list(pkgconf_client_t *client, pkgconf_audit_log_dependency(client, pkgdep, depnode); - eflags |= pkgconf_pkg_traverse_main(client, pkgdep, func, data, depth - 1, skip_flags); + eflags |= pkgconf_pkg_traverse_main(client, pkgdep, func, data, depth - 1, skip_flags, iter_flags); next: pkgconf_pkg_unref(client, pkgdep); } @@ -1661,7 +1786,8 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client, pkgconf_pkg_traverse_func_t func, void *data, int maxdepth, - unsigned int skip_flags) + unsigned int skip_flags, + unsigned int iter_flags) { unsigned int eflags = PKGCONF_PKG_ERRF_OK; @@ -1683,7 +1809,7 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client, if ((root->flags & PKGCONF_PKG_PROPF_VIRTUAL) != PKGCONF_PKG_PROPF_VIRTUAL || (client->flags & PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL) != PKGCONF_PKG_PKGF_SKIP_ROOT_VIRTUAL) { if (func != NULL) - func(client, root, data); + func(client, root, data, iter_flags); } if (!(client->flags & PKGCONF_PKG_PKGF_SKIP_CONFLICTS) && root->conflicts.head != NULL) @@ -1696,7 +1822,7 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client, } PKGCONF_TRACE(client, "%s: walking 'Requires' list", root->id); - eflags = pkgconf_pkg_walk_list(client, root, &root->required, func, data, maxdepth, skip_flags); + eflags = pkgconf_pkg_walk_list(client, root, &root->required, func, data, maxdepth, skip_flags, iter_flags); if (eflags != PKGCONF_PKG_ERRF_OK) return eflags; @@ -1704,18 +1830,14 @@ pkgconf_pkg_traverse_main(pkgconf_client_t *client, { PKGCONF_TRACE(client, "%s: walking 'Requires.shared' list", root->id); - eflags = pkgconf_pkg_walk_list(client, root, &root->requires_shared, func, data, maxdepth, skip_flags); + eflags = pkgconf_pkg_walk_list(client, root, &root->requires_shared, func, data, maxdepth, skip_flags, iter_flags); if (eflags != PKGCONF_PKG_ERRF_OK) return eflags; } PKGCONF_TRACE(client, "%s: walking 'Requires.private' list", root->id); - /* XXX: ugly */ - client->flags |= PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE; - eflags = pkgconf_pkg_walk_list(client, root, &root->requires_private, func, data, maxdepth, skip_flags); - client->flags &= ~PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE; - + eflags = pkgconf_pkg_walk_list(client, root, &root->requires_private, func, data, maxdepth, skip_flags, iter_flags | PKGCONF_PKG_ITERF_PRIVATE); if (eflags != PKGCONF_PKG_ERRF_OK) return eflags; @@ -1730,8 +1852,7 @@ pkgconf_pkg_traverse(pkgconf_client_t *client, int maxdepth, unsigned int skip_flags) { - if (root->flags & PKGCONF_PKG_PROPF_VIRTUAL) - client->serial++; + client->serial++; if ((client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) == 0) { @@ -1742,45 +1863,51 @@ pkgconf_pkg_traverse(pkgconf_client_t *client, // Skip shared deps in static mode skip_flags |= PKGCONF_PKG_DEPF_SHARED; - return pkgconf_pkg_traverse_main(client, root, func, data, maxdepth, skip_flags); + return pkgconf_pkg_traverse_main(client, root, func, data, maxdepth, skip_flags, PKGCONF_PKG_ITERF_NONE); } static void -pkgconf_pkg_cflags_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) +pkgconf_pkg_cflags_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags) { - pkgconf_list_t *list = data; + pkgconf_fragment_cursor_t *cursor = data; pkgconf_node_t *node; + (void) iter_flags; + PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags.head, node) { pkgconf_fragment_t *frag = node->data; - pkgconf_fragment_copy(client, list, frag, false); + pkgconf_fragment_copy_cursor(client, cursor, frag, false); } } static void -pkgconf_pkg_cflags_private_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) +pkgconf_pkg_cflags_private_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags) { - pkgconf_list_t *list = data; + pkgconf_fragment_cursor_t *cursor = data; pkgconf_node_t *node; + (void) iter_flags; + PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags_private.head, node) { pkgconf_fragment_t *frag = node->data; - pkgconf_fragment_copy(client, list, frag, true); + pkgconf_fragment_copy_cursor(client, cursor, frag, true); } } static void -pkgconf_pkg_cflags_shared_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) +pkgconf_pkg_cflags_shared_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags) { - pkgconf_list_t *list = data; + pkgconf_fragment_cursor_t *cursor = data; pkgconf_node_t *node; + (void) iter_flags; + PKGCONF_FOREACH_LIST_ENTRY(pkg->cflags_shared.head, node) { pkgconf_fragment_t *frag = node->data; - pkgconf_fragment_copy(client, list, frag, true); + pkgconf_fragment_copy_cursor(client, cursor, frag, true); } } @@ -1804,37 +1931,41 @@ pkgconf_pkg_cflags(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t unsigned int eflag; unsigned int skip_flags = (client->flags & PKGCONF_PKG_PKGF_DONT_FILTER_INTERNAL_CFLAGS) == 0 ? PKGCONF_PKG_DEPF_INTERNAL : 0; pkgconf_list_t frags = PKGCONF_LIST_INITIALIZER; + pkgconf_fragment_cursor_t cursor; - eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_collect, &frags, maxdepth, skip_flags); + pkgconf_fragment_cursor_init(&cursor, &frags); + + eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_collect, &cursor, maxdepth, skip_flags); if (eflag == PKGCONF_PKG_ERRF_OK) { if (client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS) { - eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_private_collect, &frags, maxdepth, skip_flags); + eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_private_collect, &cursor, maxdepth, skip_flags); } else { - eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_shared_collect, &frags, maxdepth, skip_flags); + eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_cflags_shared_collect, &cursor, maxdepth, skip_flags); } } + pkgconf_fragment_cursor_deinit(&cursor); + if (eflag != PKGCONF_PKG_ERRF_OK) { pkgconf_fragment_free(&frags); return eflag; } - pkgconf_fragment_copy_list(client, list, &frags); - pkgconf_fragment_free(&frags); + pkgconf_list_splice(list, &frags); return eflag; } static void -pkgconf_pkg_libs_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) +pkgconf_pkg_libs_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags) { - pkgconf_list_t *list = data; + pkgconf_fragment_cursor_t *cursor = data; pkgconf_node_t *node; if (!(client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) && pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE) @@ -1843,7 +1974,7 @@ pkgconf_pkg_libs_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *dat PKGCONF_FOREACH_LIST_ENTRY(pkg->libs.head, node) { pkgconf_fragment_t *frag = node->data; - pkgconf_fragment_copy(client, list, frag, (client->flags & PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE) != 0); + pkgconf_fragment_copy_cursor(client, cursor, frag, (iter_flags & PKGCONF_PKG_ITERF_PRIVATE) != 0); } if (client->flags & PKGCONF_PKG_PKGF_MERGE_PRIVATE_FRAGMENTS) @@ -1851,7 +1982,7 @@ pkgconf_pkg_libs_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *dat PKGCONF_FOREACH_LIST_ENTRY(pkg->libs_private.head, node) { pkgconf_fragment_t *frag = node->data; - pkgconf_fragment_copy(client, list, frag, true); + pkgconf_fragment_copy_cursor(client, cursor, frag, true); } } else @@ -1859,7 +1990,7 @@ pkgconf_pkg_libs_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *dat PKGCONF_FOREACH_LIST_ENTRY(pkg->libs_shared.head, node) { pkgconf_fragment_t *frag = node->data; - pkgconf_fragment_copy(client, list, frag, true); + pkgconf_fragment_copy_cursor(client, cursor, frag, true); } } } @@ -1882,8 +2013,11 @@ unsigned int pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t *list, int maxdepth) { unsigned int eflag; + pkgconf_fragment_cursor_t cursor; - eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_libs_collect, list, maxdepth, 0); + pkgconf_fragment_cursor_init(&cursor, list); + eflag = pkgconf_pkg_traverse(client, root, pkgconf_pkg_libs_collect, &cursor, maxdepth, 0); + pkgconf_fragment_cursor_deinit(&cursor); if (eflag != PKGCONF_PKG_ERRF_OK) { @@ -1895,11 +2029,13 @@ pkgconf_pkg_libs(pkgconf_client_t *client, pkgconf_pkg_t *root, pkgconf_list_t * } static void -pkgconf_pkg_link_abi_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) +pkgconf_pkg_link_abi_collect(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags) { pkgconf_list_t *list = data; pkgconf_node_t *node; + (void) iter_flags; + if (!(client->flags & PKGCONF_PKG_PKGF_SEARCH_PRIVATE) && pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE) return; diff --git a/contrib/pkgconf/libpkgconf/queue.c b/contrib/pkgconf/libpkgconf/queue.c index ff4e049612c0..7100449d2404 100644 --- a/contrib/pkgconf/libpkgconf/queue.c +++ b/contrib/pkgconf/libpkgconf/queue.c @@ -52,11 +52,22 @@ pkgconf_queue_push_dependency(pkgconf_list_t *list, const pkgconf_dependency_t * if (pkgq == NULL) return; - pkgconf_buffer_append(&depbuf, dep->package); - if (dep->version != NULL) - pkgconf_buffer_append_fmt(&depbuf, " %s %s", pkgconf_pkg_get_comparator(dep), dep->version); + if (!pkgconf_buffer_append(&depbuf, dep->package) || + (dep->version != NULL && + !pkgconf_buffer_append_fmt(&depbuf, " %s %s", pkgconf_pkg_get_comparator(dep), dep->version))) + { + pkgconf_buffer_finalize(&depbuf); + free(pkgq); + return; + } pkgq->package = pkgconf_buffer_freeze(&depbuf); + if (pkgq->package == NULL) + { + free(pkgq); + return; + } + pkgconf_node_insert_tail(&pkgq->iter, pkgq, list); } @@ -80,6 +91,12 @@ pkgconf_queue_push(pkgconf_list_t *list, const char *package) return; pkgq->package = strdup(package); + if (pkgq->package == NULL) + { + free(pkgq); + return; + } + pkgconf_node_insert_tail(&pkgq->iter, pkgq, list); } @@ -137,8 +154,10 @@ pkgconf_queue_free(pkgconf_list_t *list) } static void -pkgconf_queue_mark_public(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data) +pkgconf_queue_mark_public(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *data, unsigned int iter_flags) { + (void) iter_flags; + if (pkg->flags & PKGCONF_PKG_PROPF_VISITED_PRIVATE) { pkgconf_list_t *list = data; @@ -161,13 +180,15 @@ static unsigned int pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client, pkgconf_pkg_t *root, void *data, - int maxdepth); + int maxdepth, + unsigned int iter_flags); static inline unsigned int pkgconf_queue_collect_dependencies_walk(pkgconf_client_t *client, pkgconf_list_t *deplist, void *data, - int depth) + int depth, + unsigned int iter_flags) { unsigned int eflags = PKGCONF_PKG_ERRF_OK; pkgconf_node_t *node; @@ -191,12 +212,12 @@ pkgconf_queue_collect_dependencies_walk(pkgconf_client_t *client, if (pkg->serial == client->serial) continue; - if (client->flags & PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE) + if (iter_flags & PKGCONF_PKG_ITERF_PRIVATE) pkg->flags |= PKGCONF_PKG_PROPF_VISITED_PRIVATE; else pkg->flags &= ~PKGCONF_PKG_PROPF_VISITED_PRIVATE; - eflags |= pkgconf_queue_collect_dependencies_main(client, pkg, data, depth - 1); + eflags |= pkgconf_queue_collect_dependencies_main(client, pkg, data, depth - 1, iter_flags); flattened_dep = pkgconf_dependency_copy(client, dep); if (flattened_dep == NULL) @@ -215,7 +236,8 @@ static unsigned int pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client, pkgconf_pkg_t *root, void *data, - int maxdepth) + int maxdepth, + unsigned int iter_flags) { unsigned int eflags = PKGCONF_PKG_ERRF_OK; @@ -233,24 +255,20 @@ pkgconf_queue_collect_dependencies_main(pkgconf_client_t *client, { PKGCONF_TRACE(client, "%s: collecting shared dependencies, level %d", root->id, maxdepth); - eflags = pkgconf_queue_collect_dependencies_walk(client, &root->requires_shared, data, maxdepth); + eflags = pkgconf_queue_collect_dependencies_walk(client, &root->requires_shared, data, maxdepth, iter_flags); if (eflags != PKGCONF_PKG_ERRF_OK) return eflags; } PKGCONF_TRACE(client, "%s: collecting private dependencies, level %d", root->id, maxdepth); - /* XXX: ugly */ - const unsigned int saved_flags = client->flags; - client->flags |= PKGCONF_PKG_PKGF_ITER_PKG_IS_PRIVATE; - eflags = pkgconf_queue_collect_dependencies_walk(client, &root->requires_private, data, maxdepth); - client->flags = saved_flags; + eflags = pkgconf_queue_collect_dependencies_walk(client, &root->requires_private, data, maxdepth, iter_flags | PKGCONF_PKG_ITERF_PRIVATE); if (eflags != PKGCONF_PKG_ERRF_OK) return eflags; PKGCONF_TRACE(client, "%s: collecting public dependencies, level %d", root->id, maxdepth); - eflags = pkgconf_queue_collect_dependencies_walk(client, &root->required, data, maxdepth); + eflags = pkgconf_queue_collect_dependencies_walk(client, &root->required, data, maxdepth, iter_flags); if (eflags != PKGCONF_PKG_ERRF_OK) return eflags; @@ -266,7 +284,7 @@ pkgconf_queue_collect_dependencies(pkgconf_client_t *client, int maxdepth) { ++client->serial; - return pkgconf_queue_collect_dependencies_main(client, root, data, maxdepth); + return pkgconf_queue_collect_dependencies_main(client, root, data, maxdepth, PKGCONF_PKG_ITERF_NONE); } static inline unsigned int @@ -306,6 +324,13 @@ pkgconf_queue_collect_conflicts(pkgconf_client_t *client, } flattened_conflict->why = strdup(pkg->id); + if (flattened_conflict->why == NULL) + { + eflags |= PKGCONF_PKG_ERRF_DEPGRAPH_BREAK; + pkgconf_dependency_unref(client, flattened_conflict); + continue; + } + pkgconf_node_insert(&flattened_conflict->iter, flattened_conflict, &world->conflicts); } } diff --git a/contrib/pkgconf/libpkgconf/stdinc.h b/contrib/pkgconf/libpkgconf/stdinc.h index 4bc0596cb88e..b3704a810300 100644 --- a/contrib/pkgconf/libpkgconf/stdinc.h +++ b/contrib/pkgconf/libpkgconf/stdinc.h @@ -33,10 +33,15 @@ #include #include #include +#include -#ifdef _WIN32 -# define WIN32_LEAN_AND_MEAN -# include +#if defined(_WIN32) || defined(__OS2__) +# ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# include +# else +# include /* readlink */ +# endif # include # include /* for _setmode() */ # include @@ -62,7 +67,7 @@ # define SIZE_FMT_SPECIFIER "%u" # endif # endif -# ifndef ssize_t +# if !(defined(ssize_t) || defined(__OS2__)) # ifndef __MINGW32__ # include # else @@ -70,7 +75,7 @@ # endif # define ssize_t SSIZE_T # endif -# ifndef __MINGW32__ +# if !(defined (__MINGW32__) || defined(__OS2__)) # include "win-dirent.h" # else # include @@ -78,9 +83,13 @@ # define PKGCONF_ITEM_SIZE (_MAX_PATH + 1024) # define PKG_CONFIG_PATH_SEP_S ";" # define PKG_DIR_SEP_S '\\' -# define strcasecmp _stricmp -# define strncasecmp _strnicmp -# define realpath(N,R) _fullpath((R),(N),_MAX_PATH) +# ifndef __OS2__ +# define strcasecmp _stricmp +# define strncasecmp _strnicmp +# define realpath(N,R) _fullpath((R),(N),_MAX_PATH) +# else +# define _setmode(h, m) if (!isatty((h))) setmode((h), (m)) +# endif #else # define PATH_DEV_NULL "/dev/null" # define SIZE_FMT_SPECIFIER "%zu" @@ -89,7 +98,6 @@ # endif # include # include -# include # include # include // open # include // basename/dirname diff --git a/contrib/pkgconf/libpkgconf/tuple.c b/contrib/pkgconf/libpkgconf/tuple.c index 1e349711f0ec..35406c9971fe 100644 --- a/contrib/pkgconf/libpkgconf/tuple.c +++ b/contrib/pkgconf/libpkgconf/tuple.c @@ -73,7 +73,7 @@ pkgconf_tuple_find_global(pkgconf_client_t *client, const char *key) v = pkgconf_variable_find(&client->global_vars, key); - pkgconf_buffer_reset(&client->_scratch_buffer); + pkgconf_buffer_rewind(&client->_scratch_buffer); (void) pkgconf_variable_eval(client, &client->global_vars, v, &client->_scratch_buffer, &saw_sysroot); return pkgconf_buffer_str_or_empty(&client->_scratch_buffer); @@ -195,28 +195,42 @@ pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *list, const ch return NULL; } - v->flags = flags; - if (!parse) { - pkgconf_buffer_reset(&v->bcbuf); - pkgconf_bytecode_emit_text(&v->bcbuf, dequote_value, strlen(dequote_value)); - pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf); + if (!pkgconf_bytecode_emit_text(&rhs_bcbuf, dequote_value, strlen(dequote_value))) + { + pkgconf_buffer_finalize(&rhs_bcbuf); + free(dequote_value); + return NULL; + } + + free(dequote_value); + } + else + { + if (!pkgconf_bytecode_compile(&rhs_bcbuf, dequote_value)) + { + pkgconf_buffer_finalize(&rhs_bcbuf); + free(dequote_value); + return NULL; + } + free(dequote_value); - return (pkgconf_tuple_t *) v; } - pkgconf_bytecode_compile(&rhs_bcbuf, dequote_value); - free(dequote_value); - /* ugh, we are doing var=${var}/foo stuff */ - if (pkgconf_bytecode_references_var(&rhs_bcbuf, key)) + if (parse && pkgconf_bytecode_references_var(&rhs_bcbuf, key)) { pkgconf_buffer_t old_bcbuf = PKGCONF_BUFFER_INITIALIZER; pkgconf_buffer_t new_bcbuf = PKGCONF_BUFFER_INITIALIZER; /* preserve the old bytecode */ - pkgconf_buffer_copy(&v->bcbuf, &old_bcbuf); + if (!pkgconf_buffer_copy(&v->bcbuf, &old_bcbuf)) + { + pkgconf_buffer_finalize(&old_bcbuf); + pkgconf_buffer_finalize(&rhs_bcbuf); + return NULL; + } /* splice the selfrefs, using the old bytecode instead of ${var} */ if (!pkgconf_bytecode_rewrite_selfrefs(&new_bcbuf, &rhs_bcbuf, key, &old_bcbuf)) @@ -229,15 +243,22 @@ pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *list, const ch } /* copy the spliced bytecode back to &rhs_bcbuf, replacing its contents */ - pkgconf_buffer_copy(&new_bcbuf, &rhs_bcbuf); + if (!pkgconf_buffer_copy(&new_bcbuf, &rhs_bcbuf)) + { + pkgconf_buffer_finalize(&old_bcbuf); + pkgconf_buffer_finalize(&new_bcbuf); + pkgconf_buffer_finalize(&rhs_bcbuf); + return NULL; + } pkgconf_buffer_finalize(&old_bcbuf); pkgconf_buffer_finalize(&new_bcbuf); } - pkgconf_buffer_copy(&rhs_bcbuf, &v->bcbuf); + pkgconf_buffer_finalize(&v->bcbuf); + v->bcbuf = rhs_bcbuf; + v->flags = flags; pkgconf_bytecode_from_buffer(&v->bc, &v->bcbuf); - pkgconf_buffer_finalize(&rhs_bcbuf); return (pkgconf_tuple_t *) v; } @@ -267,7 +288,7 @@ pkgconf_tuple_find(pkgconf_client_t *client, pkgconf_list_t *list, const char *k if (v == NULL) v = pkgconf_variable_find(&client->global_vars, key); - pkgconf_buffer_reset(&client->_scratch_buffer); + pkgconf_buffer_rewind(&client->_scratch_buffer); (void) pkgconf_variable_eval(client, list, v, &client->_scratch_buffer, NULL); diff --git a/contrib/pkgconf/libpkgconf/variable.c b/contrib/pkgconf/libpkgconf/variable.c index fa39390910f5..7288b629ae43 100644 --- a/contrib/pkgconf/libpkgconf/variable.c +++ b/contrib/pkgconf/libpkgconf/variable.c @@ -32,20 +32,18 @@ pkgconf_variable_t * pkgconf_variable_new(const char *key) { pkgconf_variable_t *v; + size_t keylen; if (key == NULL) return NULL; - v = calloc(1, sizeof(*v)); + keylen = strlen(key); + v = calloc(1, sizeof(*v) + keylen + 1); if (v == NULL) return NULL; - v->key = strdup(key); - if (v->key == NULL) - { - free(v); - return NULL; - } + v->key = (char *)(v + 1); + memcpy(v->key, key, keylen + 1); return v; } @@ -57,7 +55,6 @@ pkgconf_variable_free(pkgconf_variable_t *v) return; pkgconf_buffer_finalize(&v->bcbuf); - free(v->key); free(v); } @@ -160,3 +157,32 @@ pkgconf_variable_eval_str(pkgconf_client_t *client, return pkgconf_buffer_freeze(&out); } + +char * +pkgconf_variable_eval_name(pkgconf_client_t *client, + const pkgconf_list_t *vars, + const char *varname) +{ + pkgconf_buffer_t varbuf = PKGCONF_BUFFER_INITIALIZER; + const pkgconf_buffer_t *sysroot_dir = PKGCONF_BUFFER_FROM_STR(client->sysroot_dir); + bool saw_sysroot = false; + pkgconf_variable_t *v; + + pkgconf_bytecode_eval_ctx_t ctx = { + .client = client, + .vars = vars, + }; + + v = pkgconf_bytecode_eval_lookup_var(&ctx, varname, strlen(varname)); + (void) pkgconf_variable_eval(client, vars, v, &varbuf, &saw_sysroot); + + if (!(client->flags & PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES) && + !saw_sysroot && pkgconf_path_is_plausible(&varbuf)) + { + /* if sysroot is set, and value does not already begin with sysroot */ + if (!pkgconf_buffer_has_prefix(&varbuf, sysroot_dir)) + pkgconf_buffer_prepend(&varbuf, pkgconf_buffer_str_or_empty(sysroot_dir)); + } + + return pkgconf_buffer_freeze(&varbuf); +} diff --git a/contrib/pkgconf/man/pccritic.1 b/contrib/pkgconf/man/pccritic.1 new file mode 100644 index 000000000000..881c5c90bedd --- /dev/null +++ b/contrib/pkgconf/man/pccritic.1 @@ -0,0 +1,138 @@ +.\" Copyright (c) 2026 pkgconf authors (see AUTHORS). +.\" +.\" Permission to use, copy, modify, and/or distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" This software is provided 'as is' and without any warranty, express or +.\" implied. In no event shall the authors be liable for any damages arising +.\" from the use of this software. +.Dd June 28, 2026 +.Dt PCCRITIC 1 +.Os +.Sh NAME +.Nm pccritic +.Nd a quality scorer for pkg-config files +.Sh SYNOPSIS +.Nm +.Op Ar options +.Ar module-or-file ... +.Sh DESCRIPTION +.Nm +inspects +.Xr pc 5 +files and reports quality findings, assigning each file a score from 0 to 100 +and a letter grade from A to F. +It is intended both as an interactive aid for package authors and as a check +that can be run in continuous integration. +.Pp +Each command-line argument is treated as a target. +If an argument contains a slash or ends in +.Pa .pc +it is interpreted as a path to a file; otherwise it is resolved as a module +name from the search path, exactly as +.Xr pkgconf 1 +would resolve it. +A file that +.Xr pkgconf 1 +refuses to load because it omits a required field is still scanned directly so +that the most broken files can be scored. +.Pp +Findings are classified by severity. +The score begins at 100 and each finding subtracts a fixed penalty: 25 for a +.Em critical +finding, 10 for a +.Em major +finding, 4 for a +.Em minor +finding, and 1 for an +.Em info +finding. +The result is clamped to the range 0 to 100. +Grades are assigned as A for 90 and above, B for 80, C for 70, D for 60, and F +below 60. +.Pp +The checks cover required and recommended metadata, version sanity, +relocatability of the +.Ic libdir +and +.Ic includedir +variables, hygiene of the +.Ic Cflags +and +.Ic Libs +fields, the +.Ic Requires +and +.Ic Requires.private +relationship, and basic file-formatting style. +.Pp +The +.Ar options +are as follows: +.Bl -tag -width indent +.It Fl -about +Print the version number, the Copyright notice, and the license of the +.Nm +program to standard output and exit. +.It Fl -version +Print the version number of the +.Nm +program to standard output and exit. +.It Fl -help +Print a short usage summary to standard output and exit. +.It Fl -quiet +Print only the score and grade for each target, one per line, instead of the +full list of findings. +.It Fl -min-score Ar n +Exit with a non-zero status if any target scores below +.Ar n . +This is useful for failing a continuous-integration job when a file's quality +regresses below a threshold. +.It Fl -color Ns Op = Ns Ar when +Control colorized output. +.Ar when +may be +.Cm auto +(the default), +.Cm always , +or +.Cm never . +When +.Cm auto , +color is enabled only when standard output is a terminal and the +.Ev NO_COLOR +environment variable is not set. +Giving +.Fl -color +without a value is equivalent to +.Cm always . +.It Fl -define-variable Ns = Ns Ar varname Ns = Ns Ar value +Define +.Ar varname +as +.Ar value . +This affects how variables in the inspected file are expanded. +.El +.Sh EXIT STATUS +.Nm +exits 0 on success. +It exits non-zero if a target could not be loaded, if the command line is +invalid, or if +.Fl -min-score +was given and a target scored below the threshold. +.Sh EXAMPLES +Score an installed module by name: +.Pp +.Dl $ pccritic zlib +.Pp +Score a file before installation and fail if it grades below a C: +.Pp +.Dl $ pccritic --min-score 70 ./mylib.pc +.Pp +Summarize every file in a directory: +.Pp +.Dl $ pccritic --quiet /usr/lib/pkgconfig/*.pc +.Sh SEE ALSO +.Xr pkgconf 1 , +.Xr pc 5 diff --git a/contrib/pkgconf/man/pkgconf.1 b/contrib/pkgconf/man/pkgconf.1 index b1bdbbb5290e..b3b74a12508c 100644 --- a/contrib/pkgconf/man/pkgconf.1 +++ b/contrib/pkgconf/man/pkgconf.1 @@ -7,7 +7,7 @@ .\" This software is provided 'as is' and without any warranty, express or .\" implied. In no event shall the authors be liable for any damages arising .\" from the use of this software. -.Dd June 23, 2026 +.Dd September 8, 2026 .Dt PKGCONF 1 .Os .Sh NAME @@ -117,8 +117,7 @@ options: .It Single-module output options: .Fl -path , -.Fl -print-variables , -.Fl -variable : +.Fl -print-variables : If any of these options is specified, only the first .Ar module argument is used, all other arguments are silently ignored, @@ -128,8 +127,9 @@ Depth-one output options: .Fl -print-provides , .Fl -modversion , .Fl -print-requires , +.Fl -print-requires-private , and -.Fl -print-requires-private : +.Fl -variable : If any of these options is specified, only modules explicitly specified on the command line are inspected and no dependency resolution is attempted. @@ -288,6 +288,19 @@ Most other options and all command line arguments are ignored. Ignore .Sq Conflicts rules in modules. +This option is implied by the options which merely report metadata about the +requested modules rather than combining them into a build, namely +.Fl -license , +.Fl -license-file , +.Fl -modversion , +.Fl -path , +.Fl -print-provides , +.Fl -print-requires , +.Fl -print-requires-private , +.Fl -print-variables , +.Fl -source , +and +.Fl -variable . .It Fl -keep-system-cflags , Fl -keep-system-libs Keep CFLAGS or linker flag fragments that would be filtered due to being included by default in the compiler. @@ -384,6 +397,12 @@ is greater than the requested number. .It Fl -maximum-traverse-depth Ns = Ns Ar depth Impose a limit on the allowed depth in the dependency graph. +The default +.Ar depth +is 256. +Set +.Ar depth +to \-1 to allow unlimited traversal. For example, a .Ar depth of 2 restricts the resolver from acting on child @@ -570,12 +589,11 @@ This option implies and .Fl -errors-to-stdout . .It Fl -variable Ns = Ns Ar varname -For the first -.Ar module -given on the command line, print the value of the variable with the name +For each specified +.Ar module , +print the value of the variable with the name .Ar varname -to standard output. -Any subsequent arguments are silently ignored. +to standard output in command-line order. This option implies .Fl -maximum-traverse-depth Ns =1 and overrides and disables all @@ -621,9 +639,15 @@ in the same way as .It Ev DESTDIR If set to the same value as .Ev PKG_CONFIG_SYSROOT_DIR , -behave in the same way as if +follow .Ev PKG_CONFIG_FDO_SYSROOT_RULES -is set. +for variable lookups, but disable automatic sysroot injection into +.Fl I +and +.Fl L +fragments to avoid prefixing paths with +.Ev DESTDIR +twice. If .Ev PKG_CONFIG_SYSROOT_DIR is not set or set to a different value, @@ -693,6 +717,7 @@ For more details, see the command line option, which overrides this variable. .It Ev PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH Impose a limit on the allowed depth in the dependency graph. +Set this variable to \-1 to allow unlimited traversal. This variable overrides the .Fl -maximum-traverse-depth option, but is overridden by the other options mentioned there. diff --git a/contrib/pkgconf/man/spdxtool.1 b/contrib/pkgconf/man/spdxtool.1 index 2bc7dfb165a3..e9766b409992 100644 --- a/contrib/pkgconf/man/spdxtool.1 +++ b/contrib/pkgconf/man/spdxtool.1 @@ -19,12 +19,12 @@ .Ar module ... .Sh DESCRIPTION .Nm -is a program which generates a JSON-LD formated SPDX Lite 3.0.1 software bill of +is a program which generates a JSON-LD formatted SPDX Lite 3.0.1 software bill of materials (SBOM) for a given set of pkg-config modules. The output of this tool can then be translated into other SBOM formats as necessary. -More documention about SDPX 3.0.1 can be found from: +More documentation about SDPX 3.0.1 can be found from: .Lk https://spdx.github.io/spdx-spec/v3.0.1/ .Pp The @@ -46,7 +46,7 @@ Set agent name-property in /Core/Agent-class. Default is 'Default' .It Fl -creation-time Set create-property time in /Core/CreationInfo-class. -SPDX documentation recomends using ISO 8601-formated time which is: YYYY-MM-DDThh:mm:ssZ. +SPDX documentation recommends using ISO 8601-formatted time which is: YYYY-MM-DDThh:mm:ssZ. Default is document creation time. This takes precedence over the .Ev SOURCE_DATE_EPOCH diff --git a/contrib/pkgconf/meson.build b/contrib/pkgconf/meson.build index 798095165d94..7b4c373597b9 100644 --- a/contrib/pkgconf/meson.build +++ b/contrib/pkgconf/meson.build @@ -1,5 +1,5 @@ project('pkgconf', 'c', - version : '2.9.93', + version : '3.0.8', license : 'ISC', default_options : [ 'c_std=c99', @@ -18,6 +18,7 @@ if cc.get_argument_syntax() != 'msvc' ) endif add_project_arguments( + '-D_ATFILE_SOURCE', '-D_BSD_SOURCE', '-D_DARWIN_C_SOURCE', '-D_DEFAULT_SOURCE', @@ -65,6 +66,7 @@ endif cdata = configuration_data() check_functions = [ + ['getc_unlocked', 'stdio.h'], ['strndup', 'string.h'], ['strdup', 'string.h'], ['strncasecmp', 'strings.h'], @@ -73,11 +75,13 @@ check_functions = [ ['pledge', 'unistd.h'], ['unveil', 'unistd.h'], ['readlinkat', 'unistd.h'], + ['mkdtemp', 'stdlib.h'], ] # Feature-test macros mirroring those defined globally by the build, so that # the function probes below see the same declarations as the actual sources. feature_macros = { + '_ATFILE_SOURCE': '', '_BSD_SOURCE': '', '_DARWIN_C_SOURCE': '', '_DEFAULT_SOURCE': '', @@ -128,10 +132,14 @@ else cdata.set('HAVE_DECL_NL_LANGINFO_L', 0) endif -default_path = [] -foreach f : ['libdir', 'datadir'] - default_path += [join_paths(get_option('prefix'), get_option(f), 'pkgconfig')] -endforeach +PKG_DEFAULT_PATH = get_option('with-pkg-config-dir') +if PKG_DEFAULT_PATH == '' + default_path = [] + foreach f : ['libdir', 'datadir'] + default_path += [join_paths(get_option('prefix'), get_option(f), 'pkgconfig')] + endforeach + PKG_DEFAULT_PATH = ':'.join(default_path) +endif personality_path = [] foreach f : ['libdir', 'datadir'] @@ -150,11 +158,11 @@ if SYSTEM_INCLUDEDIR != '' else cdata.set_quoted('SYSTEM_INCLUDEDIR', join_paths(get_option('prefix'), get_option('includedir'))) endif -cdata.set_quoted('PKG_DEFAULT_PATH', ':'.join(default_path)) +cdata.set_quoted('PKG_DEFAULT_PATH', PKG_DEFAULT_PATH) cdata.set_quoted('PERSONALITY_PATH', ':'.join(personality_path)) cdata.set_quoted('PACKAGE_NAME', meson.project_name()) cdata.set_quoted('PACKAGE_VERSION', meson.project_version()) -cdata.set_quoted('PACKAGE_BUGREPORT', 'https://todo.sr.ht/~kaniini/pkgconf') +cdata.set_quoted('PACKAGE_BUGREPORT', 'https://github.com/pkgconf/pkgconf/issues') cdata.set('abs_top_srcdir', meson.current_source_dir()) cdata.set('abs_top_builddir', meson.current_build_dir()) @@ -210,11 +218,9 @@ if fuzzing subdir('fuzzer') endif -# If we have a new enough meson override the dependency so that only -# `dependency('libpkgconf')` is required from the consumer -if meson.version().version_compare('>= 0.54.0') - meson.override_dependency('libpkgconf', dep_libpkgconf) -endif +# override the dependency so that only `dependency('libpkgconf')` is +# required from the consumer +meson.override_dependency('libpkgconf', dep_libpkgconf) pkg = import('pkgconfig') pkg.generate(libpkgconf, @@ -278,6 +284,16 @@ spdxtool_exe = executable('spdxtool', include_directories : include_directories('cli', 'cli/spdxtool'), install : true) +pccritic_exe = executable('pccritic', + 'cli/pccritic/main.c', + 'cli/pccritic/critic.c', + 'cli/getopt_long.c', + windows_manifest, + link_with : libpkgconf, + c_args : build_static, + include_directories : include_directories('cli', 'cli/pccritic'), + install : true) + test_runner_exe = executable('test-runner', 'cli/core.c', 'cli/getopt_long.c', @@ -287,7 +303,8 @@ test_runner_exe = executable('test-runner', link_with : libpkgconf, c_args : build_static, include_directories : cli_include, - install : false) + install : false, + build_by_default : false) api_tests = [ 'audit', @@ -313,7 +330,8 @@ foreach t : api_tests link_with : libpkgconf, c_args : build_static, include_directories : [include_directories('.'), include_directories('tests/api')], - install : false) + install : false, + build_by_default : false) test('api-' + t, exe) endforeach @@ -330,9 +348,27 @@ test_api_serialize_exe = executable('test-api-serialize', link_with : libpkgconf, c_args : build_static, include_directories : [include_directories('.'), include_directories('tests/api'), include_directories('cli/spdxtool')], - install : false) + install : false, + build_by_default : false) test('api-serialize', test_api_serialize_exe) +# Unit test for spdxtool's util uri encode. +test_api_util_exe = executable('test-api-util', + 'tests/api/test-util.c', + 'cli/spdxtool/core.c', + 'cli/spdxtool/software.c', + 'cli/spdxtool/serialize.c', + 'cli/spdxtool/simplelicensing.c', + 'cli/spdxtool/util.c', + windows_manifest, + link_with : libpkgconf, + c_args : build_static, + include_directories : [include_directories('.'), include_directories('tests/api'), include_directories('cli/spdxtool')], + install : false, + build_by_default : false) +test('api-util', test_api_util_exe) + + # Allocation-failure (OOM) tests. These drive the shared fuzzer/alloc-inject # fault injector through the linker's --wrap, so they are built wherever --wrap # is supported: glibc and musl Linux (GNU ld / lld), and skipped on macOS ld64 @@ -352,24 +388,29 @@ oom_wrap_args = [ ] if build_oom_tests - # Unit test: fault-inject spdxtool's own allocations. It links libpkgconf - # normally (shared); only spdxtool's compiled-in allocations are wrapped, - # which is exactly what we want to fail here. - test_api_oom_spdxtool_exe = executable('test-api-oom-spdxtool', - 'tests/api/test-oom-spdxtool.c', - 'fuzzer/alloc-inject.c', - 'cli/spdxtool/core.c', - 'cli/spdxtool/software.c', - 'cli/spdxtool/serialize.c', - 'cli/spdxtool/simplelicensing.c', - 'cli/spdxtool/util.c', - windows_manifest, - link_with : libpkgconf, - c_args : build_static, - link_args : oom_wrap_args, - include_directories : [include_directories('.'), include_directories('tests/api'), include_directories('cli/spdxtool'), include_directories('fuzzer')], - install : false) - test('api-oom-spdxtool', test_api_oom_spdxtool_exe) + # Unit test: fault-inject spdxtool's own allocations. It requires a shared + # libpkgconf so that the linker's --wrap only reaches spdxtool's compiled-in + # allocations. With a static libpkgconf its allocations are wrapped too, + # invalidating the test's expectation that every injected failure makes the + # spdxtool operation fail. + if libtype != 'static' + test_api_oom_spdxtool_exe = executable('test-api-oom-spdxtool', + 'tests/api/test-oom-spdxtool.c', + 'fuzzer/alloc-inject.c', + 'cli/spdxtool/core.c', + 'cli/spdxtool/software.c', + 'cli/spdxtool/serialize.c', + 'cli/spdxtool/simplelicensing.c', + 'cli/spdxtool/util.c', + windows_manifest, + link_with : libpkgconf, + c_args : build_static, + link_args : oom_wrap_args, + include_directories : [include_directories('.'), include_directories('tests/api'), include_directories('cli/spdxtool'), include_directories('fuzzer')], + install : false, + build_by_default : false) + test('api-oom-spdxtool', test_api_oom_spdxtool_exe) + endif # Replay the existing parser/solver fuzz targets over their seed corpus, # deterministically and without libFuzzer, so the libpkgconf OOM paths they @@ -394,7 +435,8 @@ if build_oom_tests c_args : build_static, link_args : oom_wrap_args, include_directories : [include_directories('.'), include_directories('fuzzer')], - install : false) + install : false, + build_by_default : false) # The exhaustive per-input injection loop is slow under ASAN; give it room. test('fuzz-replay-' + r[0], replay_exe, args : [r[1]], timeout : 120) endforeach @@ -416,13 +458,14 @@ test_suites = [ 'tuple', 'bomtool', 'spdxtool', + 'pccritic', 'symlink' ] foreach t : test_suites test(t, test_runner_exe, args : ['--test-fixtures', fixtures_dir, '--tool-dir', tool_dir, join_paths(meson.current_source_dir(), 't', t)], - depends : [pkgconf_exe, spdxtool_exe, bomtool_exe]) + depends : [pkgconf_exe, spdxtool_exe, bomtool_exe, pccritic_exe]) endforeach install_man('man/bomtool.1') @@ -431,6 +474,7 @@ install_man('man/pkg.m4.7') install_man('man/pc.5') install_man('man/pkgconf-personality.5') install_man('man/spdxtool.1') +install_man('man/pccritic.1') install_data('pkg.m4', install_dir: 'share/aclocal') install_data('AUTHORS', install_dir: 'share/doc/pkgconf') install_data('README.md', install_dir: 'share/doc/pkgconf') @@ -440,6 +484,9 @@ if host_machine.system() == 'windows' conf_data = configuration_data() conf_data.set('VERSION', meson.project_version()) conf_data.set('EXE', pkgconf_exe.full_path()) + conf_data.set('BOMTOOL_EXE', bomtool_exe.full_path()) + conf_data.set('SPDXTOOL_EXE', spdxtool_exe.full_path()) + conf_data.set('PCCRITIC_EXE', pccritic_exe.full_path()) conf_data.set('DLL', libpkgconf.full_path()) conf_data.set('BUILD_TYPE', libtype) @@ -470,7 +517,7 @@ if host_machine.system() == 'windows' if wix.found() msi = custom_target( msi_filename, - input: [wxsfile, licensefile, pkgconf_exe], + input: [wxsfile, licensefile, pkgconf_exe, bomtool_exe, spdxtool_exe, pccritic_exe], output: msi_filename, command: [wix, 'build', wxsfile, '-arch', wix_arch, '-ext', 'WixToolset.UI.wixext', '-o', msi_filename], ) diff --git a/contrib/pkgconf/meson_options.txt b/contrib/pkgconf/meson_options.txt index 21dbc368253e..22f93e6cd670 100644 --- a/contrib/pkgconf/meson_options.txt +++ b/contrib/pkgconf/meson_options.txt @@ -1,3 +1,10 @@ +option( + 'with-pkg-config-dir', + type: 'string', + value: '', + description: 'Specify the default package search path (default {prefix}/{libdir}/pkgconfig:{prefix}/{datadir}/pkgconfig)' +) + option( 'with-system-libdir', type: 'string', diff --git a/contrib/pkgconf/pkgconf.manifest.in b/contrib/pkgconf/pkgconf.manifest.in index 8c6cb75b8146..8f4c51e178d6 100644 --- a/contrib/pkgconf/pkgconf.manifest.in +++ b/contrib/pkgconf/pkgconf.manifest.in @@ -4,6 +4,7 @@ UTF-8 + true diff --git a/contrib/pkgconf/pkgconf.wxs.in b/contrib/pkgconf/pkgconf.wxs.in index 2a4498cf6b51..fe3019a94403 100644 --- a/contrib/pkgconf/pkgconf.wxs.in +++ b/contrib/pkgconf/pkgconf.wxs.in @@ -19,7 +19,7 @@ - + @@ -41,6 +41,21 @@ Source="@EXE@" KeyPath="yes" /> + + + + + + + + + &1 Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib1 Environment: PKG_CONFIG_EARLY_TRACE=1 -ExpectedStdout: installing default unveil handler +ExpectedStdout: installing custom unveil handler MatchStdout: partial ExpectedExitCode: 0 SkipPlatforms: lite diff --git a/contrib/pkgconf/t/cli/maximum-traverse-depth-invalid-env.test b/contrib/pkgconf/t/cli/maximum-traverse-depth-invalid-env.test new file mode 100644 index 000000000000..ca607c7a1ced --- /dev/null +++ b/contrib/pkgconf/t/cli/maximum-traverse-depth-invalid-env.test @@ -0,0 +1,4 @@ +Tool: pkgconf +ToolArgs: --libs bar +Environment: PKG_CONFIG_MAXIMUM_TRAVERSE_DEPTH=-2 +ExpectedExitCode: 1 diff --git a/contrib/pkgconf/t/cli/maximum-traverse-depth-invalid.test b/contrib/pkgconf/t/cli/maximum-traverse-depth-invalid.test new file mode 100644 index 000000000000..eca960c68703 --- /dev/null +++ b/contrib/pkgconf/t/cli/maximum-traverse-depth-invalid.test @@ -0,0 +1,3 @@ +Tool: pkgconf +ToolArgs: --maximum-traverse-depth=invalid --libs bar +ExpectedExitCode: 1 diff --git a/contrib/pkgconf/t/cli/maximum-traverse-depth-unlimited.test b/contrib/pkgconf/t/cli/maximum-traverse-depth-unlimited.test new file mode 100644 index 000000000000..0a23a988c416 --- /dev/null +++ b/contrib/pkgconf/t/cli/maximum-traverse-depth-unlimited.test @@ -0,0 +1,5 @@ +Tool: pkgconf +ToolArgs: --maximum-traverse-depth=-1 --libs bar +Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib1 +ExpectedStdout: -L/test/lib -lbar -lfoo +ExpectedExitCode: 0 diff --git a/contrib/pkgconf/t/cli/single-package-limit.out b/contrib/pkgconf/t/cli/single-package-limit.out new file mode 100644 index 000000000000..17474c01dc8a --- /dev/null +++ b/contrib/pkgconf/t/cli/single-package-limit.out @@ -0,0 +1,2 @@ +pcfiledir +qux diff --git a/contrib/pkgconf/t/cli/single-package-limit.test b/contrib/pkgconf/t/cli/single-package-limit.test new file mode 100644 index 000000000000..45a0b1b8a4c6 --- /dev/null +++ b/contrib/pkgconf/t/cli/single-package-limit.test @@ -0,0 +1,4 @@ +Tool: pkgconf +ToolArgs: --with-path=%TEST_FIXTURES_DIR%/lib1 --print-variables maxpkg-first maxpkg-second +ExpectedStdoutFile: single-package-limit.out +ExpectedExitCode: 0 diff --git a/contrib/pkgconf/t/cli/variable-multiple-packages.test b/contrib/pkgconf/t/cli/variable-multiple-packages.test new file mode 100644 index 000000000000..771890423605 --- /dev/null +++ b/contrib/pkgconf/t/cli/variable-multiple-packages.test @@ -0,0 +1,4 @@ +Tool: pkgconf +ToolArgs: --with-path=%TEST_FIXTURES_DIR%/lib1 --variable=qux maxpkg-first maxpkg-second +ExpectedStdout: first-value second-value +ExpectedExitCode: 0 diff --git a/contrib/pkgconf/t/parser/escape-layers-bare-var-libs.test b/contrib/pkgconf/t/parser/escape-layers-bare-var-libs.test new file mode 100644 index 000000000000..d9a6a7248ab5 --- /dev/null +++ b/contrib/pkgconf/t/parser/escape-layers-bare-var-libs.test @@ -0,0 +1,4 @@ +PackageSearchPath: lib1 +Query: escape-layers-bare-var +WantedFlags: libs +ExpectedStdout: -L/test/a\ dir -la -Wl,--foo\\bar diff --git a/contrib/pkgconf/t/parser/escape-layers-cflags.test b/contrib/pkgconf/t/parser/escape-layers-cflags.test new file mode 100644 index 000000000000..74db0a6ebcaf --- /dev/null +++ b/contrib/pkgconf/t/parser/escape-layers-cflags.test @@ -0,0 +1,4 @@ +PackageSearchPath: lib1 +Query: escape-layers +WantedFlags: cflags +ExpectedStdout: -I/test/a\ dir -DBS=x\\y -DLIT=p\\q -DLITSP=p\ q diff --git a/contrib/pkgconf/t/parser/escape-layers-libs.test b/contrib/pkgconf/t/parser/escape-layers-libs.test new file mode 100644 index 000000000000..58f63894fb74 --- /dev/null +++ b/contrib/pkgconf/t/parser/escape-layers-libs.test @@ -0,0 +1,4 @@ +PackageSearchPath: lib1 +Query: escape-layers +WantedFlags: libs +ExpectedStdout: -L/test/a\ dir/lib -L/test/lit\ eral -la diff --git a/contrib/pkgconf/t/parser/fragment-escaped-space-var-cflags.test b/contrib/pkgconf/t/parser/fragment-escaped-space-var-cflags.test new file mode 100644 index 000000000000..d08cc8c0cfec --- /dev/null +++ b/contrib/pkgconf/t/parser/fragment-escaped-space-var-cflags.test @@ -0,0 +1,4 @@ +PackageSearchPath: lib1 +Query: fragment-escaped-space-var +WantedFlags: cflags +ExpectedStdout: -I/test/a\ dir/b\ dir diff --git a/contrib/pkgconf/t/parser/fragment-escaped-space-var-libs.test b/contrib/pkgconf/t/parser/fragment-escaped-space-var-libs.test new file mode 100644 index 000000000000..b7c2e3877700 --- /dev/null +++ b/contrib/pkgconf/t/parser/fragment-escaped-space-var-libs.test @@ -0,0 +1,4 @@ +PackageSearchPath: lib1 +Query: fragment-escaped-space-var +WantedFlags: libs +ExpectedStdout: -L/test/a\ dir/b\ dir -la diff --git a/contrib/pkgconf/t/parser/self-referential-fragment.test b/contrib/pkgconf/t/parser/self-referential-fragment.test new file mode 100644 index 000000000000..0e51aa9780b0 --- /dev/null +++ b/contrib/pkgconf/t/parser/self-referential-fragment.test @@ -0,0 +1,4 @@ +PackageSearchPath: lib1 +Query: self-referential-fragment +WantedFlags: cflags +ExpectedStdout: $\{x\} diff --git a/contrib/pkgconf/t/parser/spaces-in-paths.test b/contrib/pkgconf/t/parser/spaces-in-paths.test new file mode 100644 index 000000000000..6ac5d0722e97 --- /dev/null +++ b/contrib/pkgconf/t/parser/spaces-in-paths.test @@ -0,0 +1,4 @@ +PackageSearchPath: lib1 +Query: spaces-in-paths +WantedFlags: cflags +ExpectedStdout: -I/test\ with\ spaces/include -I/test\ with\ spaces/include/subdir diff --git a/contrib/pkgconf/t/pccritic/about.test b/contrib/pkgconf/t/pccritic/about.test new file mode 100644 index 000000000000..4776f9b81ae3 --- /dev/null +++ b/contrib/pkgconf/t/pccritic/about.test @@ -0,0 +1,5 @@ +Tool: pccritic +ToolArgs: --about +ExpectedStdout: pccritic +MatchStdout: Partial +ExpectedExitCode: 0 diff --git a/contrib/pkgconf/t/pccritic/help.test b/contrib/pkgconf/t/pccritic/help.test new file mode 100644 index 000000000000..257492b7cb04 --- /dev/null +++ b/contrib/pkgconf/t/pccritic/help.test @@ -0,0 +1,5 @@ +Tool: pccritic +ToolArgs: --help +ExpectedStdout: usage: pccritic +MatchStdout: Partial +ExpectedExitCode: 0 diff --git a/contrib/pkgconf/t/pccritic/min-score-invalid.test b/contrib/pkgconf/t/pccritic/min-score-invalid.test new file mode 100644 index 000000000000..c808770fafd3 --- /dev/null +++ b/contrib/pkgconf/t/pccritic/min-score-invalid.test @@ -0,0 +1,3 @@ +Tool: pccritic +ToolArgs: --min-score invalid polluted +ExpectedExitCode: 1 diff --git a/contrib/pkgconf/t/pccritic/min-score-out-of-range.test b/contrib/pkgconf/t/pccritic/min-score-out-of-range.test new file mode 100644 index 000000000000..62a015d1a664 --- /dev/null +++ b/contrib/pkgconf/t/pccritic/min-score-out-of-range.test @@ -0,0 +1,3 @@ +Tool: pccritic +ToolArgs: --min-score 101 polluted +ExpectedExitCode: 1 diff --git a/contrib/pkgconf/t/pccritic/min-score.test b/contrib/pkgconf/t/pccritic/min-score.test new file mode 100644 index 000000000000..35e05d3aa22d --- /dev/null +++ b/contrib/pkgconf/t/pccritic/min-score.test @@ -0,0 +1,4 @@ +Tool: pccritic +ToolArgs: --quiet --min-score 90 polluted +Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-pccritic +ExpectedExitCode: 1 diff --git a/contrib/pkgconf/t/pccritic/missing-field.test b/contrib/pkgconf/t/pccritic/missing-field.test new file mode 100644 index 000000000000..435b8183aa6e --- /dev/null +++ b/contrib/pkgconf/t/pccritic/missing-field.test @@ -0,0 +1,5 @@ +Tool: pccritic +ToolArgs: --quiet %TEST_FIXTURES_DIR%/lib-pccritic/nodesc.pc +ExpectedStdout: 75/100 (C) +MatchStdout: Partial +ExpectedExitCode: 0 diff --git a/contrib/pkgconf/t/pccritic/no-arguments.test b/contrib/pkgconf/t/pccritic/no-arguments.test new file mode 100644 index 000000000000..4aa6a4639df1 --- /dev/null +++ b/contrib/pkgconf/t/pccritic/no-arguments.test @@ -0,0 +1,2 @@ +Tool: pccritic +ExpectedExitCode: 1 diff --git a/contrib/pkgconf/t/pccritic/perfect.test b/contrib/pkgconf/t/pccritic/perfect.test new file mode 100644 index 000000000000..2fa8c3c1b660 --- /dev/null +++ b/contrib/pkgconf/t/pccritic/perfect.test @@ -0,0 +1,5 @@ +Tool: pccritic +ToolArgs: --quiet perfect +Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-pccritic +ExpectedStdout: perfect: 100/100 (A) +ExpectedExitCode: 0 diff --git a/contrib/pkgconf/t/pccritic/polluted.test b/contrib/pkgconf/t/pccritic/polluted.test new file mode 100644 index 000000000000..5e2d214060f9 --- /dev/null +++ b/contrib/pkgconf/t/pccritic/polluted.test @@ -0,0 +1,5 @@ +Tool: pccritic +ToolArgs: --quiet polluted +Environment: PKG_CONFIG_PATH=%TEST_FIXTURES_DIR%/lib-pccritic +ExpectedStdout: polluted: 80/100 (B) +ExpectedExitCode: 0 diff --git a/contrib/pkgconf/t/pccritic/unknown-package.test b/contrib/pkgconf/t/pccritic/unknown-package.test new file mode 100644 index 000000000000..484f557355b4 --- /dev/null +++ b/contrib/pkgconf/t/pccritic/unknown-package.test @@ -0,0 +1,3 @@ +Tool: pccritic +ToolArgs: this-module-does-not-exist +ExpectedExitCode: 1 diff --git a/contrib/pkgconf/t/pccritic/version.test b/contrib/pkgconf/t/pccritic/version.test new file mode 100644 index 000000000000..223f2b6a9757 --- /dev/null +++ b/contrib/pkgconf/t/pccritic/version.test @@ -0,0 +1,5 @@ +Tool: pccritic +ToolArgs: --version +ExpectedStdout: pccritic +MatchStdout: Partial +ExpectedExitCode: 0 diff --git a/contrib/pkgconf/t/solver/conflicts-license.test b/contrib/pkgconf/t/solver/conflicts-license.test new file mode 100644 index 000000000000..dd16ab85bb5f --- /dev/null +++ b/contrib/pkgconf/t/solver/conflicts-license.test @@ -0,0 +1,7 @@ +PackageSearchPath: lib1 +Query: conflicts, foo +WantedFlags: dump-license +ExpectedStdout: conflicts: NOASSERTION +ExpectedStdout: foo: ISC +ExpectedExitCode: 0 +MatchStdout: partial diff --git a/contrib/pkgconf/t/solver/conflicts-modversion.test b/contrib/pkgconf/t/solver/conflicts-modversion.test new file mode 100644 index 000000000000..ac2e4d3fc57e --- /dev/null +++ b/contrib/pkgconf/t/solver/conflicts-modversion.test @@ -0,0 +1,7 @@ +PackageSearchPath: lib1 +Query: conflicts, foo +WantedFlags: modversion +ExpectedStdout: 1.2.3 +ExpectedStdout: 1.2.3 +ExpectedExitCode: 0 +MatchStdout: partial diff --git a/contrib/pkgconf/t/solver/conflicts-print-provides.test b/contrib/pkgconf/t/solver/conflicts-print-provides.test new file mode 100644 index 000000000000..d8f1159907bd --- /dev/null +++ b/contrib/pkgconf/t/solver/conflicts-print-provides.test @@ -0,0 +1,7 @@ +PackageSearchPath: lib1 +Query: conflicts, foo +WantedFlags: print-provides +ExpectedStdout: conflicts = 1.2.3 +ExpectedStdout: foo = 1.2.3 +ExpectedExitCode: 0 +MatchStdout: partial diff --git a/contrib/pkgconf/t/solver/conflicts-print-requires.test b/contrib/pkgconf/t/solver/conflicts-print-requires.test new file mode 100644 index 000000000000..fb3a3b8054ee --- /dev/null +++ b/contrib/pkgconf/t/solver/conflicts-print-requires.test @@ -0,0 +1,4 @@ +PackageSearchPath: lib1 +Query: conflicts, foo +WantedFlags: print-requires +ExpectedExitCode: 0 diff --git a/contrib/pkgconf/t/sysroot/fdo-sysroot-system-path-filtering.test b/contrib/pkgconf/t/sysroot/fdo-sysroot-system-path-filtering.test new file mode 100644 index 000000000000..efc0b2ea496c --- /dev/null +++ b/contrib/pkgconf/t/sysroot/fdo-sysroot-system-path-filtering.test @@ -0,0 +1,7 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +Environment: PKG_CONFIG_SYSTEM_INCLUDE_PATH=/sysroot/test/include/foo +Environment: PKG_CONFIG_FDO_SYSROOT_RULES=1 +PackageSearchPath: lib1 +Query: foo +WantedFlags: cflags +ExpectedStdout: -fPIC diff --git a/contrib/pkgconf/t/sysroot/fdo-sysroot-variable-not-rewritten.test b/contrib/pkgconf/t/sysroot/fdo-sysroot-variable-not-rewritten.test new file mode 100644 index 000000000000..0ab911ac4020 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/fdo-sysroot-variable-not-rewritten.test @@ -0,0 +1,6 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +Environment: PKG_CONFIG_FDO_SYSROOT_RULES=1 +PackageSearchPath: lib1 +Query: foo +WantVariable: prefix +ExpectedStdout: /test diff --git a/contrib/pkgconf/t/sysroot/idirafter-munge-sysroot.test b/contrib/pkgconf/t/sysroot/idirafter-munge-sysroot.test index 987ef4ab0015..b063a50ae3bf 100644 --- a/contrib/pkgconf/t/sysroot/idirafter-munge-sysroot.test +++ b/contrib/pkgconf/t/sysroot/idirafter-munge-sysroot.test @@ -2,5 +2,4 @@ Environment: PKG_CONFIG_SYSROOT_DIR=%TEST_FIXTURES_DIR% PackageSearchPath: lib1 Query: idirafter WantedFlags: cflags -ExpectedStdout: -idirafter %TEST_FIXTURES_DIR%/opt/bad/include -MatchStdout: partial +ExpectedStdout: -idirafter %TEST_FIXTURES_DIR%/opt/bad/include -idirafter %TEST_FIXTURES_DIR%/opt/bad2/include diff --git a/contrib/pkgconf/t/sysroot/inject-bare-sysrootdir.test b/contrib/pkgconf/t/sysroot/inject-bare-sysrootdir.test new file mode 100644 index 000000000000..f08a7dc8ddb4 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-bare-sysrootdir.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +PackageSearchPath: lib1 +Query: sysroot-inject-bare +WantedFlags: cflags +ExpectedStdout: -I/sysroot diff --git a/contrib/pkgconf/t/sysroot/inject-common-prefix-derived.test b/contrib/pkgconf/t/sysroot/inject-common-prefix-derived.test new file mode 100644 index 000000000000..2ad9f94ef53a --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-common-prefix-derived.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/usr +PackageSearchPath: lib1 +Query: sysroot-inject-prefix +WantedFlags: cflags +ExpectedStdout: -I/usr/include diff --git a/contrib/pkgconf/t/sysroot/inject-common-prefix-hardcoded.test b/contrib/pkgconf/t/sysroot/inject-common-prefix-hardcoded.test new file mode 100644 index 000000000000..ac493fa04464 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-common-prefix-hardcoded.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/usr +PackageSearchPath: lib1 +Query: sysroot-inject-hardcoded +WantedFlags: cflags +ExpectedStdout: -I/usr/opt/x diff --git a/contrib/pkgconf/t/sysroot/inject-common-prefix-literal.test b/contrib/pkgconf/t/sysroot/inject-common-prefix-literal.test new file mode 100644 index 000000000000..3f5428590d18 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-common-prefix-literal.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/usr +PackageSearchPath: lib1 +Query: sysroot-inject-literal +WantedFlags: cflags +ExpectedStdout: -I/usr/sysroot/opt/x diff --git a/contrib/pkgconf/t/sysroot/inject-explicit-cflags.test b/contrib/pkgconf/t/sysroot/inject-explicit-cflags.test new file mode 100644 index 000000000000..842f14150607 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-explicit-cflags.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +PackageSearchPath: lib1 +Query: sysroot-inject-explicit +WantedFlags: cflags +ExpectedStdout: -I/sysroot/opt/x diff --git a/contrib/pkgconf/t/sysroot/inject-explicit-libs.test b/contrib/pkgconf/t/sysroot/inject-explicit-libs.test new file mode 100644 index 000000000000..0c2a20f00584 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-explicit-libs.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +PackageSearchPath: lib1 +Query: sysroot-inject-explicit +WantedFlags: libs +ExpectedStdout: -L/sysroot/opt/lib -lx diff --git a/contrib/pkgconf/t/sysroot/inject-hardcoded-cflags.test b/contrib/pkgconf/t/sysroot/inject-hardcoded-cflags.test new file mode 100644 index 000000000000..a67bcce1d19b --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-hardcoded-cflags.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +PackageSearchPath: lib1 +Query: sysroot-inject-hardcoded +WantedFlags: cflags +ExpectedStdout: -I/sysroot/opt/x diff --git a/contrib/pkgconf/t/sysroot/inject-hardcoded-libs.test b/contrib/pkgconf/t/sysroot/inject-hardcoded-libs.test new file mode 100644 index 000000000000..7834a7d5eeb6 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-hardcoded-libs.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +PackageSearchPath: lib1 +Query: sysroot-inject-hardcoded +WantedFlags: libs +ExpectedStdout: -L/sysroot/opt/lib -lx diff --git a/contrib/pkgconf/t/sysroot/inject-isystem-attached.test b/contrib/pkgconf/t/sysroot/inject-isystem-attached.test new file mode 100644 index 000000000000..ff1d0398acf3 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-isystem-attached.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +PackageSearchPath: lib1 +Query: sysroot-inject-isystem-attached +WantedFlags: cflags +ExpectedStdout: -isystem /sysroot/opt/x diff --git a/contrib/pkgconf/t/sysroot/inject-isystem-explicit.test b/contrib/pkgconf/t/sysroot/inject-isystem-explicit.test new file mode 100644 index 000000000000..085dd82cb117 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-isystem-explicit.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +PackageSearchPath: lib1 +Query: sysroot-inject-isystem-explicit +WantedFlags: cflags +ExpectedStdout: -isystem /sysroot/opt/x diff --git a/contrib/pkgconf/t/sysroot/inject-isystem-literal.test b/contrib/pkgconf/t/sysroot/inject-isystem-literal.test new file mode 100644 index 000000000000..32b668090a8b --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-isystem-literal.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +PackageSearchPath: lib1 +Query: sysroot-inject-isystem-literal +WantedFlags: cflags +ExpectedStdout: -isystem /sysroot/opt/x diff --git a/contrib/pkgconf/t/sysroot/inject-isystem-separate.test b/contrib/pkgconf/t/sysroot/inject-isystem-separate.test new file mode 100644 index 000000000000..5074e02857b7 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-isystem-separate.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +PackageSearchPath: lib1 +Query: sysroot-inject-isystem-separate +WantedFlags: cflags +ExpectedStdout: -isystem /sysroot/opt/x diff --git a/contrib/pkgconf/t/sysroot/inject-literal-prefixed.test b/contrib/pkgconf/t/sysroot/inject-literal-prefixed.test new file mode 100644 index 000000000000..b7db03a74c3a --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-literal-prefixed.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +PackageSearchPath: lib1 +Query: sysroot-inject-literal +WantedFlags: cflags +ExpectedStdout: -I/sysroot/opt/x diff --git a/contrib/pkgconf/t/sysroot/inject-mixed-fragments.test b/contrib/pkgconf/t/sysroot/inject-mixed-fragments.test new file mode 100644 index 000000000000..6bc0ee84ae56 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-mixed-fragments.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +PackageSearchPath: lib1 +Query: sysroot-inject-mixed +WantedFlags: cflags +ExpectedStdout: -I/sysroot/a -I/sysroot/b diff --git a/contrib/pkgconf/t/sysroot/inject-multi-fragment-var.test b/contrib/pkgconf/t/sysroot/inject-multi-fragment-var.test new file mode 100644 index 000000000000..4feaddd9582c --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-multi-fragment-var.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +PackageSearchPath: lib1 +Query: sysroot-inject-multi-fragment +WantedFlags: libs +ExpectedStdout: -L/sysroot/a -L/sysroot/b diff --git a/contrib/pkgconf/t/sysroot/inject-prefix-derived.test b/contrib/pkgconf/t/sysroot/inject-prefix-derived.test new file mode 100644 index 000000000000..51dda7aff0bc --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-prefix-derived.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/sysroot +PackageSearchPath: lib1 +Query: sysroot-inject-prefix +WantedFlags: cflags +ExpectedStdout: -I/sysroot/usr/include diff --git a/contrib/pkgconf/t/sysroot/inject-root-sysroot-hardcoded.test b/contrib/pkgconf/t/sysroot/inject-root-sysroot-hardcoded.test new file mode 100644 index 000000000000..4fd0406c5072 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-root-sysroot-hardcoded.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/ +PackageSearchPath: lib1 +Query: sysroot-inject-hardcoded +WantedFlags: cflags +ExpectedStdout: -I/opt/x diff --git a/contrib/pkgconf/t/sysroot/inject-root-sysroot-isystem.test b/contrib/pkgconf/t/sysroot/inject-root-sysroot-isystem.test new file mode 100644 index 000000000000..28402766a6d2 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/inject-root-sysroot-isystem.test @@ -0,0 +1,5 @@ +Environment: PKG_CONFIG_SYSROOT_DIR=/ +PackageSearchPath: lib1 +Query: sysroot-inject-isystem-explicit +WantedFlags: cflags +ExpectedStdout: -isystem /opt/x diff --git a/contrib/pkgconf/t/sysroot/isystem-munge-sysroot.test b/contrib/pkgconf/t/sysroot/isystem-munge-sysroot.test index 7960eb527260..6bbb7af5d2f6 100644 --- a/contrib/pkgconf/t/sysroot/isystem-munge-sysroot.test +++ b/contrib/pkgconf/t/sysroot/isystem-munge-sysroot.test @@ -2,5 +2,4 @@ Environment: PKG_CONFIG_SYSROOT_DIR=%TEST_FIXTURES_DIR% PackageSearchPath: lib1 Query: isystem WantedFlags: cflags -ExpectedStdout: -isystem %TEST_FIXTURES_DIR%/opt/bad/include -MatchStdout: partial +ExpectedStdout: -isystem %TEST_FIXTURES_DIR%/opt/bad/include -isystem %TEST_FIXTURES_DIR%/opt/bad2/include diff --git a/contrib/pkgconf/t/sysroot/windows-drive-path-no-inject.test b/contrib/pkgconf/t/sysroot/windows-drive-path-no-inject.test new file mode 100644 index 000000000000..ad541fd9da92 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/windows-drive-path-no-inject.test @@ -0,0 +1,6 @@ +SkipPlatforms: unix haiku lite +Environment: PKG_CONFIG_SYSROOT_DIR=C:\dir\install_dir +PackageSearchPath: lib1 +Query: windows-sysroot-libdir +WantedFlags: libs +ExpectedStdout: -LC:/dir/install_dir/usr/local/lib -lproject diff --git a/contrib/pkgconf/t/sysroot/windows-sysroot-inject.test b/contrib/pkgconf/t/sysroot/windows-sysroot-inject.test new file mode 100644 index 000000000000..12cb6bf928b0 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/windows-sysroot-inject.test @@ -0,0 +1,6 @@ +SkipPlatforms: unix haiku lite +Environment: PKG_CONFIG_SYSROOT_DIR=C:\sr +PackageSearchPath: lib1 +Query: windows-sysroot-inject +WantedFlags: cflags libs +ExpectedStdout: -IC:/sr/opt/include -LC:/sr/opt/lib -linject diff --git a/contrib/pkgconf/t/sysroot/windows-system-libdir-filter.test b/contrib/pkgconf/t/sysroot/windows-system-libdir-filter.test new file mode 100644 index 000000000000..c3fdd7e8d789 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/windows-system-libdir-filter.test @@ -0,0 +1,6 @@ +SkipPlatforms: unix haiku lite +Environment: PKG_CONFIG_SYSTEM_LIBRARY_PATH=C:\sys\lib +PackageSearchPath: lib1 +Query: windows-system-libdir +WantedFlags: libs +ExpectedStdout: -lfoo diff --git a/contrib/pkgconf/t/sysroot/windows-top-builddir.test b/contrib/pkgconf/t/sysroot/windows-top-builddir.test new file mode 100644 index 000000000000..c4c0e83993d8 --- /dev/null +++ b/contrib/pkgconf/t/sysroot/windows-top-builddir.test @@ -0,0 +1,6 @@ +SkipPlatforms: unix haiku lite +Environment: PKG_CONFIG_TOP_BUILD_DIR=C:\build\dir +PackageSearchPath: lib1 +Query: windows-top-builddir +WantedFlags: libs +ExpectedStdout: -LC:/build/dir/lib -ltbd diff --git a/contrib/pkgconf/t/tuple/escaped-backslash-variable.test b/contrib/pkgconf/t/tuple/escaped-backslash-variable.test new file mode 100644 index 000000000000..76bc09d51548 --- /dev/null +++ b/contrib/pkgconf/t/tuple/escaped-backslash-variable.test @@ -0,0 +1,4 @@ +PackageSearchPath: lib1 +Query: escape-layers +WantVariable: backslash +ExpectedStdout: x\\y diff --git a/contrib/pkgconf/t/tuple/escaped-whitespace-variable-dquoted.test b/contrib/pkgconf/t/tuple/escaped-whitespace-variable-dquoted.test new file mode 100644 index 000000000000..9606f2eabcb5 --- /dev/null +++ b/contrib/pkgconf/t/tuple/escaped-whitespace-variable-dquoted.test @@ -0,0 +1,4 @@ +PackageSearchPath: lib1 +Query: escape-layers +WantVariable: quoted_dq +ExpectedStdout: item1 item2 item\ with\ spaces diff --git a/contrib/pkgconf/t/tuple/escaped-whitespace-variable-nested.test b/contrib/pkgconf/t/tuple/escaped-whitespace-variable-nested.test new file mode 100644 index 000000000000..271688b084e2 --- /dev/null +++ b/contrib/pkgconf/t/tuple/escaped-whitespace-variable-nested.test @@ -0,0 +1,4 @@ +PackageSearchPath: lib1 +Query: escape-layers +WantVariable: libdir +ExpectedStdout: /test/a\ dir/lib diff --git a/contrib/pkgconf/t/tuple/escaped-whitespace-variable-squoted.test b/contrib/pkgconf/t/tuple/escaped-whitespace-variable-squoted.test new file mode 100644 index 000000000000..499e8056bff5 --- /dev/null +++ b/contrib/pkgconf/t/tuple/escaped-whitespace-variable-squoted.test @@ -0,0 +1,4 @@ +PackageSearchPath: lib1 +Query: escape-layers +WantVariable: quoted_sq +ExpectedStdout: item1 item2 item\ with\ spaces diff --git a/contrib/pkgconf/t/tuple/escaped-whitespace-variable-unquoted.test b/contrib/pkgconf/t/tuple/escaped-whitespace-variable-unquoted.test new file mode 100644 index 000000000000..5916decb78e6 --- /dev/null +++ b/contrib/pkgconf/t/tuple/escaped-whitespace-variable-unquoted.test @@ -0,0 +1,4 @@ +PackageSearchPath: lib1 +Query: escape-layers +WantVariable: unquoted +ExpectedStdout: item1 item2 item\ with\ spaces diff --git a/contrib/pkgconf/t/tuple/escaped-whitespace-variable.test b/contrib/pkgconf/t/tuple/escaped-whitespace-variable.test new file mode 100644 index 000000000000..b7ee5a1f5823 --- /dev/null +++ b/contrib/pkgconf/t/tuple/escaped-whitespace-variable.test @@ -0,0 +1,4 @@ +PackageSearchPath: lib1 +Query: escape-layers +WantVariable: prefix +ExpectedStdout: /test/a\ dir diff --git a/contrib/pkgconf/tests/api/test-buffer.c b/contrib/pkgconf/tests/api/test-buffer.c index c17818ba3b4b..0ef1d2453d27 100644 --- a/contrib/pkgconf/tests/api/test-buffer.c +++ b/contrib/pkgconf/tests/api/test-buffer.c @@ -173,6 +173,26 @@ test_buffer_copy(void) pkgconf_buffer_finalize(&dst); } +static void +test_buffer_rejects_aliasing(void) +{ + static const pkgconf_span_t spans[] = { + { 'a', 'z' }, + }; + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + + TEST_ASSERT_TRUE(pkgconf_buffer_append(&buf, "abc")); + TEST_ASSERT_FALSE(pkgconf_buffer_append(&buf, pkgconf_buffer_str(&buf))); + TEST_ASSERT_FALSE(pkgconf_buffer_append_slice(&buf, pkgconf_buffer_str(&buf), 1)); + TEST_ASSERT_FALSE(pkgconf_buffer_prepend(&buf, pkgconf_buffer_str(&buf))); + TEST_ASSERT_FALSE(pkgconf_buffer_copy(&buf, &buf)); + TEST_ASSERT_FALSE(pkgconf_buffer_subst(&buf, &buf, "a", "x")); + TEST_ASSERT_FALSE(pkgconf_buffer_escape(&buf, &buf, spans, PKGCONF_ARRAY_SIZE(spans))); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "abc"); + + pkgconf_buffer_finalize(&buf); +} + static void test_buffer_join(void) { @@ -318,6 +338,123 @@ test_buffer_escape(void) pkgconf_buffer_finalize(&dst); } +static void +test_buffer_escape_charset(void) +{ + pkgconf_buffer_t src = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t dst = PKGCONF_BUFFER_INITIALIZER; + pkgconf_charset_t charset; + + static const pkgconf_span_t spans[] = { + { ' ', ' ' }, + { '\t', '\t' }, + }; + + pkgconf_charset_from_spans(&charset, spans, PKGCONF_ARRAY_SIZE(spans)); + + pkgconf_buffer_append(&src, "a b\tc"); + TEST_ASSERT_TRUE(pkgconf_buffer_escape_charset(&dst, &src, &charset)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&dst), "a\\ b\\\tc"); + + /* escaping into the source buffer must still be rejected */ + TEST_ASSERT_FALSE(pkgconf_buffer_escape_charset(&src, &src, &charset)); + + pkgconf_buffer_finalize(&src); + pkgconf_buffer_finalize(&dst); +} + +/* + * A charset is built a 64-bit word at a time, so every combination of span + * endpoints relative to a word boundary needs to agree with a plain span walk. + * Check each such combination, including lo > hi (an empty span). + */ +static void +test_charset_word_boundaries(void) +{ + /* every boundary class: word start/end, either side of one, and the extremes */ + static const unsigned char interesting[] = { + 0x00, 0x01, 0x3e, 0x3f, 0x40, 0x41, 0x7e, 0x7f, + 0x80, 0x81, 0xbe, 0xbf, 0xc0, 0xc1, 0xfe, 0xff, + }; + + for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(interesting); i++) + { + for (size_t j = 0; j < PKGCONF_ARRAY_SIZE(interesting); j++) + { + pkgconf_charset_t charset; + const pkgconf_span_t span = { interesting[i], interesting[j] }; + + pkgconf_charset_from_spans(&charset, &span, 1); + + for (unsigned int c = 0; c <= 0xff; c++) + { + TEST_ASSERT_EQ(pkgconf_charset_contains(&charset, (unsigned char) c), + pkgconf_span_contains((unsigned char) c, &span, 1)); + } + } + } +} + +/* + * A charset must agree with a span walk for every one of the 256 byte values, + * since it exists purely to hoist that walk out of per-byte loops. Covers the + * span sets fragment quoting uses plus the awkward edges: a span reaching 0xff, + * an empty set, and lo > hi. + */ +static void +test_charset_matches_spans(void) +{ + static const pkgconf_span_t quote_spans[] = { + { 0x00, 0x1f }, { ' ', '#' }, { '%', '\'' }, { '*', '*' }, { ';', '<' }, + { '>', '?' }, { '[', ']' }, { '`', '`' }, { '{', '}' }, { 0x7f, 0xff }, + }; + static const pkgconf_span_t quote_spans_utf8[] = { + { 0x00, 0x1f }, { ' ', '#' }, { '%', '\'' }, { '*', '*' }, { ';', '<' }, + { '>', '?' }, { '[', ']' }, { '`', '`' }, { '{', '}' }, { 0x7f, 0x7f }, + }; + static const pkgconf_span_t boundaries[] = { + { 0xff, 0xff }, { 0x00, 0x00 }, { 0x3f, 0x40 }, { 0x40, 0x41 }, + }; + static const pkgconf_span_t everything[] = { { 0x00, 0xff } }; + static const pkgconf_span_t inverted[] = { { 0x80, 0x7f } }; + /* spans which each cover exactly one word, and one which straddles all four */ + static const pkgconf_span_t words[] = { + { 0x00, 0x3f }, { 0x40, 0x7f }, { 0x80, 0xbf }, { 0xc0, 0xff }, + }; + static const pkgconf_span_t straddle[] = { { 0x01, 0xfe } }; + + const struct { + const pkgconf_span_t *spans; + size_t nspans; + } cases[] = { + { quote_spans, PKGCONF_ARRAY_SIZE(quote_spans) }, + { quote_spans_utf8, PKGCONF_ARRAY_SIZE(quote_spans_utf8) }, + { boundaries, PKGCONF_ARRAY_SIZE(boundaries) }, + { everything, PKGCONF_ARRAY_SIZE(everything) }, + { inverted, PKGCONF_ARRAY_SIZE(inverted) }, + { words, PKGCONF_ARRAY_SIZE(words) }, + { words, 1 }, + { words + 1, 1 }, + { words + 2, 1 }, + { words + 3, 1 }, + { straddle, PKGCONF_ARRAY_SIZE(straddle) }, + { quote_spans, 0 }, + }; + + for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(cases); i++) + { + pkgconf_charset_t charset; + + pkgconf_charset_from_spans(&charset, cases[i].spans, cases[i].nspans); + + for (unsigned int c = 0; c <= 0xff; c++) + { + TEST_ASSERT_EQ(pkgconf_charset_contains(&charset, (unsigned char) c), + pkgconf_span_contains((unsigned char) c, cases[i].spans, cases[i].nspans)); + } + } +} + static void test_str_eq_slice(void) { @@ -401,6 +538,7 @@ main(int argc, const char **argv) TEST_RUN(basename, test_buffer_reset); TEST_RUN(basename, test_buffer_freeze); TEST_RUN(basename, test_buffer_copy); + TEST_RUN(basename, test_buffer_rejects_aliasing); TEST_RUN(basename, test_buffer_join); TEST_RUN(basename, test_buffer_contains); TEST_RUN(basename, test_buffer_match); @@ -408,6 +546,9 @@ main(int argc, const char **argv) TEST_RUN(basename, test_buffer_subst); TEST_RUN(basename, test_buffer_subst_empty_pattern); TEST_RUN(basename, test_buffer_escape); + TEST_RUN(basename, test_buffer_escape_charset); + TEST_RUN(basename, test_charset_matches_spans); + TEST_RUN(basename, test_charset_word_boundaries); TEST_RUN(basename, test_str_eq_slice); TEST_RUN(basename, test_span_contains); TEST_RUN(basename, test_buffer_fputs_nonempty); diff --git a/contrib/pkgconf/tests/api/test-bytecode.c b/contrib/pkgconf/tests/api/test-bytecode.c index 7be48941eed9..04d244becd01 100644 --- a/contrib/pkgconf/tests/api/test-bytecode.c +++ b/contrib/pkgconf/tests/api/test-bytecode.c @@ -145,6 +145,52 @@ test_eval_null_args(void) pkgconf_client_free(client); } +static void +test_eval_malformed_bytecode(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER; + pkgconf_buffer_t empty = PKGCONF_BUFFER_INITIALIZER; + pkgconf_bytecode_t bc = { NULL, 0 }; + + TEST_ASSERT_TRUE(pkgconf_bytecode_eval(client, &vars, &bc, &out, NULL)); + + bc.len = 1; + TEST_ASSERT_FALSE(pkgconf_bytecode_eval(client, &vars, &bc, &out, NULL)); + + uint8_t truncated = 0; + bc.base = &truncated; + TEST_ASSERT_FALSE(pkgconf_bytecode_eval(client, &vars, &bc, &out, NULL)); + + pkgconf_bytecode_op_t oversized = { + .tag = PKGCONF_BYTECODE_OP_TEXT, + .size = UINT32_MAX, + }; + bc.base = (const uint8_t *) &oversized; + bc.len = sizeof oversized; + TEST_ASSERT_FALSE(pkgconf_bytecode_eval(client, &vars, &bc, &out, NULL)); + + pkgconf_bytecode_op_t unknown = { + .tag = 255, + .size = 0, + }; + bc.base = (const uint8_t *) &unknown; + bc.len = sizeof unknown; + TEST_ASSERT_FALSE(pkgconf_bytecode_eval(client, &vars, &bc, &out, NULL)); + + pkgconf_buffer_t malformed = { + .base = (char *) &oversized, + .end = (char *) &oversized + sizeof oversized, + }; + TEST_ASSERT_FALSE(pkgconf_bytecode_references_var(&malformed, "x")); + TEST_ASSERT_FALSE(pkgconf_bytecode_rewrite_selfrefs(&out, &malformed, "x", &empty)); + + pkgconf_buffer_finalize(&out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + static void test_compile_null_args(void) { @@ -523,8 +569,14 @@ test_eval_empty_input(void) { pkgconf_client_t *client = test_client_new(); pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + pkgconf_buffer_t bcbuf = PKGCONF_BUFFER_INITIALIZER; + pkgconf_bytecode_t bc; bool saw_sysroot = false; + pkgconf_bytecode_from_buffer(&bc, &bcbuf); + TEST_ASSERT_NULL(bc.base); + TEST_ASSERT_EQ(bc.len, 0); + char *out = pkgconf_bytecode_eval_str(client, &vars, "", &saw_sysroot); // An empty input may evaluate to either NULL or an empty string @@ -612,6 +664,7 @@ main(int argc, char *argv[]) TEST_RUN(basename, test_eval_undefined_variable); TEST_RUN(basename, test_eval_sysroot_detection); TEST_RUN(basename, test_eval_null_args); + TEST_RUN(basename, test_eval_malformed_bytecode); TEST_RUN(basename, test_emit_guards); TEST_RUN(basename, test_emit_text_and_eval); diff --git a/contrib/pkgconf/tests/api/test-client.c b/contrib/pkgconf/tests/api/test-client.c index ae8889b658c8..887d044c49f5 100644 --- a/contrib/pkgconf/tests/api/test-client.c +++ b/contrib/pkgconf/tests/api/test-client.c @@ -291,6 +291,26 @@ test_client_preload_from_environ(void) pkgconf_client_free(client); } +static void +test_client_preload_path_transfers_reference(void) +{ + const char *path = "test-client-preload.pc"; + FILE *f = fopen(path, "wb"); + TEST_ASSERT_NONNULL(f); + fputs("Name: preload\nDescription: preload\nVersion: 1.0\n", f); + fclose(f); + + pkgconf_client_t *client = test_client_new(); + TEST_ASSERT_TRUE(pkgconf_client_preload_path(client, path)); + TEST_ASSERT_NONNULL(client->preloaded_pkgs.head); + + pkgconf_pkg_t *pkg = client->preloaded_pkgs.head->data; + TEST_ASSERT_EQ(pkg->refcount, 1); + + pkgconf_client_free(client); + remove(path); +} + #ifndef PKGCONF_LITE static void test_client_trace_null_client(void) @@ -309,6 +329,7 @@ main(int argc, char *argv[]) TEST_RUN(basename, test_client_init_and_deinit_stack); TEST_RUN(basename, test_client_init_system_paths_from_environ); TEST_RUN(basename, test_client_preload_from_environ); + TEST_RUN(basename, test_client_preload_path_transfers_reference); TEST_RUN(basename, test_client_sysroot_dir); TEST_RUN(basename, test_client_buildroot_dir); diff --git a/contrib/pkgconf/tests/api/test-fileio.c b/contrib/pkgconf/tests/api/test-fileio.c index f0f48ff41fed..31ee1c1aed07 100644 --- a/contrib/pkgconf/tests/api/test-fileio.c +++ b/contrib/pkgconf/tests/api/test-fileio.c @@ -215,6 +215,36 @@ test_fgetline_crlf_split_across_fgets_buffer(void) pkgconf_buffer_finalize(&buf); } +#ifndef _WIN32 +static void +test_fgetline_nonseekable_stream(void) +{ + static const char contents[] = "hello\rworld\r\n"; + pkgconf_buffer_t buf = PKGCONF_BUFFER_INITIALIZER; + int fds[2]; + + TEST_ASSERT_EQ(pipe(fds), 0); + TEST_ASSERT_EQ(write(fds[1], contents, sizeof contents - 1), (ssize_t) (sizeof contents - 1)); + close(fds[1]); + + FILE *f = fdopen(fds[0], "r"); + TEST_ASSERT_NONNULL(f); + + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "hello"); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_TRUE(pkgconf_fgetline(&buf, f)); + TEST_ASSERT_STRCMP_EQ(pkgconf_buffer_str(&buf), "world"); + + pkgconf_buffer_reset(&buf); + TEST_ASSERT_FALSE(pkgconf_fgetline(&buf, f)); + + fclose(f); + pkgconf_buffer_finalize(&buf); +} +#endif + int main(int argc, const char **argv) { @@ -231,6 +261,9 @@ main(int argc, const char **argv) TEST_RUN(basename, test_fgetline_backslash_continuation_lone_cr); TEST_RUN(basename, test_fgetline_backslash_not_continuation); TEST_RUN(basename, test_fgetline_crlf_split_across_fgets_buffer); +#ifndef _WIN32 + TEST_RUN(basename, test_fgetline_nonseekable_stream); +#endif return EXIT_SUCCESS; } diff --git a/contrib/pkgconf/tests/api/test-fragment.c b/contrib/pkgconf/tests/api/test-fragment.c index 3d49145ae518..c3f2b72361df 100644 --- a/contrib/pkgconf/tests/api/test-fragment.c +++ b/contrib/pkgconf/tests/api/test-fragment.c @@ -46,6 +46,51 @@ fragment_at(const pkgconf_list_t *list, size_t index) return NULL; } +/* + * Assert that a list is internally consistent: it holds `expect` nodes, its + * cached length agrees, the terminators are NULL, and it walks to the same + * length in both directions. Relinking nodes between lists is easy to get + * subtly wrong in a way that only a structural check like this catches. + */ +static void +assert_list_integrity(const pkgconf_list_t *list, size_t expect) +{ + const pkgconf_node_t *iter; + size_t forward = 0, reverse = 0; + + TEST_ASSERT_EQ(list->length, expect); + + PKGCONF_FOREACH_LIST_ENTRY(list->head, iter) + { + if (iter->next == NULL) + TEST_ASSERT_TRUE(iter == list->tail); + + forward++; + } + + PKGCONF_FOREACH_LIST_ENTRY_REVERSE(list->tail, iter) + { + if (iter->prev == NULL) + TEST_ASSERT_TRUE(iter == list->head); + + reverse++; + } + + TEST_ASSERT_EQ(forward, expect); + TEST_ASSERT_EQ(reverse, expect); + + if (expect == 0) + { + TEST_ASSERT_NULL(list->head); + TEST_ASSERT_NULL(list->tail); + } + else + { + TEST_ASSERT_NULL(list->head->prev); + TEST_ASSERT_NULL(list->tail->next); + } +} + /* * Render a fragment list to a newly-allocated C string for assertions. * Caller frees. @@ -305,6 +350,91 @@ test_fragment_filter_keeps_nothing(void) pkgconf_client_free(client); } +static void +test_fragment_filter_splice_moves_matches(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t src = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t dst = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + /* the trailing fragment deliberately does not match: a moved node which + * keeps a stale forward link would splice the rest of src onto dst. */ + pkgconf_fragment_parse(client, &src, &vars, "-I/usr/include -L/usr/lib -I/opt/include -lfoo", 0); + + pkgconf_fragment_filter_splice(client, &dst, &src, filter_only_includes, NULL); + + /* the matches move out of src, in order; the rest stay behind */ + assert_list_integrity(&dst, 2); + assert_list_integrity(&src, 2); + TEST_ASSERT_EQ(fragment_count(&dst), 2); + TEST_ASSERT_EQ(fragment_count(&src), 2); + + const pkgconf_fragment_t *f0 = fragment_at(&dst, 0); + const pkgconf_fragment_t *f1 = fragment_at(&dst, 1); + TEST_ASSERT_NONNULL(f0); + TEST_ASSERT_NONNULL(f1); + TEST_ASSERT_EQ(f0->type, 'I'); + TEST_ASSERT_STRCMP_EQ(f0->data, "/usr/include"); + TEST_ASSERT_EQ(f1->type, 'I'); + TEST_ASSERT_STRCMP_EQ(f1->data, "/opt/include"); + + const pkgconf_fragment_t *r0 = fragment_at(&src, 0); + const pkgconf_fragment_t *r1 = fragment_at(&src, 1); + TEST_ASSERT_NONNULL(r0); + TEST_ASSERT_NONNULL(r1); + TEST_ASSERT_EQ(r0->type, 'L'); + TEST_ASSERT_EQ(r1->type, 'l'); + + pkgconf_fragment_free(&dst); + pkgconf_fragment_free(&src); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_fragment_splice_list(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t src = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t dst = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_fragment_parse(client, &dst, &vars, "-I/usr/include", 0); + pkgconf_fragment_parse(client, &src, &vars, "-lfoo -lbar", 0); + + /* splicing onto a non-empty list appends and empties the source */ + pkgconf_list_splice(&dst, &src); + + assert_list_integrity(&dst, 3); + assert_list_integrity(&src, 0); + TEST_ASSERT_EQ(fragment_count(&dst), 3); + TEST_ASSERT_EQ(fragment_count(&src), 0); + + char *rendered = render_to_string(&dst); + TEST_ASSERT_STRCMP_EQ(rendered, "-I/usr/include -lfoo -lbar"); + free(rendered); + + TEST_ASSERT_STRCMP_EQ(((const pkgconf_fragment_t *) dst.tail->data)->data, "bar"); + + /* splicing an empty source, or a list onto itself, is a no-op */ + pkgconf_list_splice(&dst, &src); + pkgconf_list_splice(&dst, &dst); + assert_list_integrity(&dst, 3); + + /* splicing onto an empty destination adopts the source wholesale */ + pkgconf_list_splice(&src, &dst); + assert_list_integrity(&src, 3); + assert_list_integrity(&dst, 0); + pkgconf_list_splice(&dst, &src); + assert_list_integrity(&dst, 3); + + pkgconf_fragment_free(&dst); + pkgconf_fragment_free(&src); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + static void test_fragment_has_system_dir_matches(void) { @@ -369,6 +499,8 @@ main(int argc, char *argv[]) TEST_RUN(basename, test_fragment_filter_only_includes); TEST_RUN(basename, test_fragment_filter_only_libnames); TEST_RUN(basename, test_fragment_filter_keeps_nothing); + TEST_RUN(basename, test_fragment_filter_splice_moves_matches); + TEST_RUN(basename, test_fragment_splice_list); TEST_RUN(basename, test_fragment_has_system_dir_matches); TEST_RUN(basename, test_fragment_has_system_dir_libs); diff --git a/contrib/pkgconf/tests/api/test-license.c b/contrib/pkgconf/tests/api/test-license.c index d77ed21a4c86..077bad9cdc00 100644 --- a/contrib/pkgconf/tests/api/test-license.c +++ b/contrib/pkgconf/tests/api/test-license.c @@ -48,7 +48,7 @@ test_license_insert_and_free(void) pkgconf_client_t *client = test_client_new(); pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; - pkgconf_license_insert(client, &licenses, PKGCONF_LICENSE_EXPRESSION, "BSD-3-Clause"); + TEST_ASSERT_TRUE(pkgconf_license_insert(client, &licenses, PKGCONF_LICENSE_EXPRESSION, "BSD-3-Clause")); TEST_ASSERT_EQ(license_count(&licenses), 1); const pkgconf_license_t *l = licenses.head->data; @@ -78,7 +78,7 @@ test_license_evaluate_single(void) pkgconf_client_t *client = test_client_new(); pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; - pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0); + TEST_ASSERT_TRUE(pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0)); TEST_ASSERT_EQ(license_count(&licenses), 1); const pkgconf_license_t *l = licenses.head->data; @@ -95,7 +95,7 @@ test_license_evaluate_or(void) pkgconf_client_t *client = test_client_new(); pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; - pkgconf_license_evaluate_str(client, &licenses, "MIT OR ISC", 0); + TEST_ASSERT_TRUE(pkgconf_license_evaluate_str(client, &licenses, "MIT OR ISC", 0)); TEST_ASSERT_EQ(license_count(&licenses), 3); @@ -113,7 +113,7 @@ test_license_evaluate_and(void) pkgconf_client_t *client = test_client_new(); pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; - pkgconf_license_evaluate_str(client, &licenses, "LGPL-2.1-only AND MIT", 0); + TEST_ASSERT_TRUE(pkgconf_license_evaluate_str(client, &licenses, "LGPL-2.1-only AND MIT", 0)); char *rendered = render_to_string(client, &licenses); TEST_ASSERT_STRCMP_EQ(rendered, "LGPL-2.1-only AND MIT"); @@ -129,8 +129,8 @@ test_license_evaluate_multiple_keys_implicit_and(void) pkgconf_client_t *client = test_client_new(); pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; - pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0); - pkgconf_license_evaluate_str(client, &licenses, "BSD-2-Clause", 0); + TEST_ASSERT_TRUE(pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0)); + TEST_ASSERT_TRUE(pkgconf_license_evaluate_str(client, &licenses, "BSD-2-Clause", 0)); char *rendered = render_to_string(client, &licenses); TEST_ASSERT_STRCMP_EQ(rendered, "BSD-3-Clause AND BSD-2-Clause"); @@ -146,7 +146,7 @@ test_license_evaluate_brackets(void) pkgconf_client_t *client = test_client_new(); pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; - pkgconf_license_evaluate_str(client, &licenses, "ISC AND (BSD-3-Clause AND BSD-2-Clause)", 0); + TEST_ASSERT_TRUE(pkgconf_license_evaluate_str(client, &licenses, "ISC AND (BSD-3-Clause AND BSD-2-Clause)", 0)); char *rendered = render_to_string(client, &licenses); TEST_ASSERT_STRCMP_EQ(rendered, "ISC AND (BSD-3-Clause AND BSD-2-Clause)"); @@ -162,7 +162,7 @@ test_license_evaluate_empty(void) pkgconf_client_t *client = test_client_new(); pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; - pkgconf_license_evaluate_str(client, &licenses, "", 0); + TEST_ASSERT_TRUE(pkgconf_license_evaluate_str(client, &licenses, "", 0)); TEST_ASSERT_EQ(license_count(&licenses), 0); pkgconf_license_free(&licenses); @@ -178,7 +178,7 @@ test_license_evaluate_sanitizes(void) /* The sanitiser strips characters outside the allowed set * (alnum, '-', '+', '(', ')', '.', ':'). A token of pure * junk should sanitise to empty and be skipped. */ - pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0); + TEST_ASSERT_TRUE(pkgconf_license_evaluate_str(client, &licenses, "BSD-3-Clause", 0)); const pkgconf_license_t *l = licenses.head->data; TEST_ASSERT_STRCMP_EQ(l->data, "BSD-3-Clause"); @@ -207,7 +207,7 @@ test_license_render_single(void) pkgconf_client_t *client = test_client_new(); pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; - pkgconf_license_insert(client, &licenses, PKGCONF_LICENSE_EXPRESSION, "MIT"); + TEST_ASSERT_TRUE(pkgconf_license_insert(client, &licenses, PKGCONF_LICENSE_EXPRESSION, "MIT")); char *rendered = render_to_string(client, &licenses); TEST_ASSERT_STRCMP_EQ(rendered, "MIT"); @@ -224,10 +224,10 @@ test_license_copy_list(void) pkgconf_list_t src = PKGCONF_LIST_INITIALIZER; pkgconf_list_t dst = PKGCONF_LIST_INITIALIZER; - pkgconf_license_evaluate_str(client, &src, "MIT OR ISC", 0); + TEST_ASSERT_TRUE(pkgconf_license_evaluate_str(client, &src, "MIT OR ISC", 0)); size_t src_count = license_count(&src); - pkgconf_license_copy_list(client, &dst, &src); + TEST_ASSERT_TRUE(pkgconf_license_copy_list(client, &dst, &src)); TEST_ASSERT_EQ(license_count(&dst), src_count); /* The copy is independent: freeing the source must not affect @@ -253,7 +253,7 @@ test_license_evaluate_long_sanitized_token(void) memset(token + 1, '_', 400); token[401] = '\0'; - pkgconf_license_evaluate_str(client, &licenses, token, 0); + TEST_ASSERT_TRUE(pkgconf_license_evaluate_str(client, &licenses, token, 0)); TEST_ASSERT_EQ(license_count(&licenses), 1); const pkgconf_license_t *l = licenses.head->data; @@ -270,13 +270,13 @@ test_license_evaluate_unterminated_quote(void) pkgconf_client_t *client = test_client_new(); pkgconf_list_t licenses = PKGCONF_LIST_INITIALIZER; - pkgconf_license_evaluate_str(client, &licenses, "\"", 0); + TEST_ASSERT_TRUE(pkgconf_license_evaluate_str(client, &licenses, "\"", 0)); TEST_ASSERT_EQ(license_count(&licenses), 0); - pkgconf_license_evaluate_str(client, &licenses, "MIT \"unterminated", 0); + TEST_ASSERT_TRUE(pkgconf_license_evaluate_str(client, &licenses, "MIT \"unterminated", 0)); TEST_ASSERT_EQ(license_count(&licenses), 0); - pkgconf_license_evaluate_str(client, &licenses, "\\", 0); + TEST_ASSERT_TRUE(pkgconf_license_evaluate_str(client, &licenses, "\\", 0)); TEST_ASSERT_EQ(license_count(&licenses), 0); pkgconf_license_free(&licenses); diff --git a/contrib/pkgconf/tests/api/test-oom-spdxtool.c b/contrib/pkgconf/tests/api/test-oom-spdxtool.c index aa3b36c1c013..c3e1838b74a7 100644 --- a/contrib/pkgconf/tests/api/test-oom-spdxtool.c +++ b/contrib/pkgconf/tests/api/test-oom-spdxtool.c @@ -40,6 +40,28 @@ oom_setup(void) spdxtool_util_set_spdx_license(g_client, "CC0-1.0"); } + +/* + * ============================================== + * util / url + * ============================================== + */ + +static void +test_oom_util_id_string(void) +{ + char *id_str = NULL; + OOM_TEST_PTR(id_str, spdxtool_util_get_spdx_id_string(g_client, "test", "test1"), free(id_str)); +} + +static void +test_oom_util_id_int(void) +{ + char *id_str = NULL; + OOM_TEST_PTR(id_str, spdxtool_util_get_spdx_id_int(g_client, "test"), free(id_str)); +} + + /* * ============================================== * core / software / simplelicensing constructors @@ -53,12 +75,20 @@ test_oom_agent_new(void) OOM_TEST_PTR(a, spdxtool_core_agent_new(g_client, "_:c1", "Agent Name"), spdxtool_core_agent_free(a)); } +static void +test_oom_tool_new(void) +{ + spdxtool_core_tool_t *a; + OOM_TEST_PTR(a, spdxtool_core_tool_new(g_client, "_:c1", "Tool Name", "Tool long Name"), spdxtool_core_tool_free(a)); +} + + static void test_oom_creation_info_new(void) { spdxtool_core_creation_info_t *c; // NULL time exercises the get_current_iso8601_time() strdup path too - OOM_TEST_PTR(c, spdxtool_core_creation_info_new(g_client, "agentid", "_:c1", NULL), + OOM_TEST_PTR(c, spdxtool_core_creation_info_new(g_client, "agentid", "toolid", "_:c1", NULL), spdxtool_core_creation_info_free(c)); } @@ -107,6 +137,40 @@ test_oom_serialize_constructors(void) OOM_TEST_PTR(v, spdxtool_serialize_value_null(), spdxtool_serialize_value_free(v)); } +static void +test_oom_serialize_to_buffer(void) +{ + spdxtool_serialize_object_list_t *object = spdxtool_serialize_object_list_new(); + TEST_ASSERT_NONNULL(object); + TEST_ASSERT_NONNULL(spdxtool_serialize_object_add_string(object, "\"key", "value")); + + spdxtool_serialize_value_t root = { + .type = SPDXTOOL_SERIALIZE_TYPE_OBJECT, + .value = { .o = object }, + }; + + for (unsigned long n = 1; ; n++) + { + pkgconf_buffer_t buffer = PKGCONF_BUFFER_INITIALIZER; + + alloc_inject_arm(n); + bool ok = spdxtool_serialize_value_to_buf(&buffer, &root, 0); + bool fired = alloc_inject_fired(); + alloc_inject_disarm(); + pkgconf_buffer_finalize(&buffer); + + if (!fired) + { + TEST_ASSERT_TRUE(ok); + break; + } + + TEST_ASSERT_FALSE(ok); + } + + spdxtool_serialize_object_list_free(object); +} + /* * ============================================================ * *_to_object serializers that depend only on their own struct @@ -125,7 +189,7 @@ test_oom_to_object(void) spdxtool_core_agent_free(agent); spdxtool_core_creation_info_t *ci = - spdxtool_core_creation_info_new(g_client, "agentid", "_:c1", "2020-01-01T00:00:00Z"); + spdxtool_core_creation_info_new(g_client, "agentid", "toolid", "_:c1", "2020-01-01T00:00:00Z"); TEST_ASSERT_NONNULL(ci); OOM_TEST_PTR(v, spdxtool_core_creation_info_to_object(g_client, ci), spdxtool_serialize_value_free(v)); @@ -147,12 +211,16 @@ main(int argc, const char **argv) oom_setup(); + TEST_RUN(basename, test_oom_util_id_string); + TEST_RUN(basename, test_oom_util_id_int); TEST_RUN(basename, test_oom_agent_new); + TEST_RUN(basename, test_oom_tool_new); TEST_RUN(basename, test_oom_creation_info_new); TEST_RUN(basename, test_oom_spdx_document_new); TEST_RUN(basename, test_oom_sbom_new); TEST_RUN(basename, test_oom_license_expression_new); TEST_RUN(basename, test_oom_serialize_constructors); + TEST_RUN(basename, test_oom_serialize_to_buffer); TEST_RUN(basename, test_oom_to_object); pkgconf_client_free(g_client); diff --git a/contrib/pkgconf/tests/api/test-queue.c b/contrib/pkgconf/tests/api/test-queue.c index e18903c2fd9d..e7000ecfceca 100644 --- a/contrib/pkgconf/tests/api/test-queue.c +++ b/contrib/pkgconf/tests/api/test-queue.c @@ -39,6 +39,10 @@ setup_fixtures(void) write_pc("qbar.pc", "Name: qbar\nDescription: bar\nVersion: 2.0\n"); write_pc("qfoo.pc", "Name: qfoo\nDescription: foo\nVersion: 1.0\nRequires: qbar >= 1.0\n"); + write_pc("qdirect.pc", + "Name: qdirect\nDescription: direct\nVersion: 1.0\n" + "Cflags: -I/direct/include\n" + "Libs: -L/direct/lib -ldirect\n"); } static void @@ -46,6 +50,7 @@ teardown_fixtures(void) { remove(FIXTURE_DIR "/qfoo.pc"); remove(FIXTURE_DIR "/qbar.pc"); + remove(FIXTURE_DIR "/qdirect.pc"); rmdir(FIXTURE_DIR); } @@ -90,6 +95,18 @@ contains_dep(const pkgconf_pkg_t *world, const char *name) return false; } +static size_t +fragment_count(const pkgconf_list_t *list) +{ + size_t n = 0; + const pkgconf_node_t *iter; + + PKGCONF_FOREACH_LIST_ENTRY(list->head, iter) + n++; + + return n; +} + static void test_queue_validate_success(void) { @@ -227,6 +244,28 @@ test_queue_apply_missing_package(void) pkgconf_client_free(client); } +static void +test_direct_pkg_helpers_traverse_each_call(void) +{ + pkgconf_client_t *client = fixture_client(); + pkgconf_pkg_t *pkg = pkgconf_pkg_find(client, "qdirect"); + pkgconf_list_t cflags = PKGCONF_LIST_INITIALIZER; + pkgconf_list_t libs = PKGCONF_LIST_INITIALIZER; + + TEST_ASSERT_NONNULL(pkg); + + TEST_ASSERT_EQ(pkgconf_pkg_cflags(client, pkg, &cflags, -1), PKGCONF_PKG_ERRF_OK); + TEST_ASSERT_GT(fragment_count(&cflags), 0); + + TEST_ASSERT_EQ(pkgconf_pkg_libs(client, pkg, &libs, -1), PKGCONF_PKG_ERRF_OK); + TEST_ASSERT_GT(fragment_count(&libs), 0); + + pkgconf_fragment_free(&cflags); + pkgconf_fragment_free(&libs); + pkgconf_pkg_unref(client, pkg); + pkgconf_client_free(client); +} + int main(int argc, char *argv[]) { @@ -243,6 +282,7 @@ main(int argc, char *argv[]) TEST_RUN(basename, test_queue_apply_success); TEST_RUN(basename, test_queue_apply_callback_failure); TEST_RUN(basename, test_queue_apply_missing_package); + TEST_RUN(basename, test_direct_pkg_helpers_traverse_each_call); teardown_fixtures(); diff --git a/contrib/pkgconf/tests/api/test-serialize.c b/contrib/pkgconf/tests/api/test-serialize.c index ef7bff0fcf95..d61c51942d9c 100644 --- a/contrib/pkgconf/tests/api/test-serialize.c +++ b/contrib/pkgconf/tests/api/test-serialize.c @@ -138,6 +138,20 @@ test_serialize_object_mixed_types(void) spdxtool_serialize_object_list_free(o); } +static void +test_serialize_object_key_escaping(void) +{ + spdxtool_serialize_object_list_t *o = spdxtool_serialize_object_list_new(); + TEST_ASSERT_NONNULL(o); + TEST_ASSERT_NONNULL(spdxtool_serialize_object_add_string(o, "\"\\\n\x01", "x")); + + char *s = render_object(o); + TEST_ASSERT_STRCMP_EQ(s, "{\n \"\\\"\\\\\\n\\u0001\": \"x\"\n}"); + + free(s); + spdxtool_serialize_object_list_free(o); +} + // Mixed-type array exercises the int/bool/null array helpers static void test_serialize_array_mixed_types(void) @@ -196,6 +210,7 @@ main(int argc, const char **argv) TEST_RUN(basename, test_serialize_value_null); TEST_RUN(basename, test_serialize_escape_sequences); TEST_RUN(basename, test_serialize_object_mixed_types); + TEST_RUN(basename, test_serialize_object_key_escaping); TEST_RUN(basename, test_serialize_array_mixed_types); TEST_RUN(basename, test_serialize_null_guards); diff --git a/contrib/pkgconf/tests/api/test-util.c b/contrib/pkgconf/tests/api/test-util.c new file mode 100644 index 000000000000..572a13e803b8 --- /dev/null +++ b/contrib/pkgconf/tests/api/test-util.c @@ -0,0 +1,116 @@ +/* + * test-util.c + * Tests for spdxtool's util functions especially URL/URI encoding. + * + * SPDX-License-Identifier: pkgconf + * + * Copyright (c) 2026 pkgconf authors (see AUTHORS). + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * This software is provided 'as is' and without any warranty, express or + * implied. In no event shall the authors be liable for any damages arising + * from the use of this software. + */ + +#include +#include +#include "test-api.h" +#include "util.h" + +static pkgconf_client_t *g_client; + +static void +util_setup(void) +{ + g_client = test_client_new(); + // Mirror cli/spdxtool/main.c: the constructors read these globals + spdxtool_util_set_uri_root(g_client, "https://example.com/test"); + spdxtool_util_set_uri_separator_colon(g_client, false); + spdxtool_util_set_spdx_version(g_client, "3.0.1"); + spdxtool_util_set_spdx_license(g_client, "CC0-1.0"); +} + +// Test set and get_uri functions +static void +test_util_set_get_uri(void) +{ + TEST_ASSERT_STRCMP_EQ(spdxtool_util_get_uri_root(g_client), "https://example.com/test"); + spdxtool_util_set_uri_root(g_client, "https://example.com/test space"); + TEST_ASSERT_STRCMP_EQ(spdxtool_util_get_uri_root(g_client), "https://example.com/test space"); +} + +// Test that uri's get escaped +static void +test_util_id_string(void) +{ + char *id_str = spdxtool_util_get_spdx_id_string(g_client, "test", "test1"); + TEST_ASSERT_STRCMP_EQ(id_str, "https://example.com/test%20space/test/test1"); + free(id_str); + id_str = spdxtool_util_get_spdx_id_string(g_client, "test^", "\\%{another text}=+\"`|"); + TEST_ASSERT_STRCMP_EQ(id_str, "https://example.com/test%20space/test%5E/%5C%3Ctext%3E%25%7Banother%20text%7D=%2B%22%60%7C"); + free(id_str); +} + +// Test that uri's get escaped +static void +test_util_id_string_urn(void) +{ + char *id_str = NULL; + spdxtool_util_set_uri_root(g_client, "urn:example:com"); + spdxtool_util_set_uri_separator_colon(g_client, ":"); + + id_str = spdxtool_util_get_spdx_id_string(g_client, "test part", "test1"); + TEST_ASSERT_STRCMP_EQ(id_str, "urn:example:com:test%20part:test1"); + free(id_str); + + id_str = spdxtool_util_get_spdx_id_string(g_client, "test part", "\\%{another text}=+\"`|,'"); + TEST_ASSERT_STRCMP_EQ(id_str, "urn:example:com:test%20part:%5C%3Ctext%3E%25%7Banother%20text%7D=%2B%22%60%7C%2C%27"); + free(id_str); +} + + +// Test that num uri's also get escaped +static void +test_util_id_int(void) +{ + char *id_str = spdxtool_util_get_spdx_id_int(g_client, "test"); + TEST_ASSERT_STRCMP_EQ(id_str, "https://example.com/test%20space/test/1"); + free(id_str); + id_str = spdxtool_util_get_spdx_id_int(g_client, "test\\^"); + TEST_ASSERT_STRCMP_EQ(id_str, "https://example.com/test%20space/test%5C%5E/2"); + free(id_str); +} + +// Test that num uri's also get escaped +static void +test_util_id_int_urn(void) +{ + char *id_str = spdxtool_util_get_spdx_id_int(g_client, "test space"); + TEST_ASSERT_STRCMP_EQ(id_str, "urn:example:com:test%20space:3"); + free(id_str); + id_str = spdxtool_util_get_spdx_id_int(g_client, "test\\^"); + TEST_ASSERT_STRCMP_EQ(id_str, "urn:example:com:test%5C%5E:4"); + free(id_str); +} + + +int +main(int argc, const char **argv) +{ + (void) argc; + const char *basename = pkgconf_path_find_basename(argv[0]); + util_setup(); + + TEST_RUN(basename, test_util_set_get_uri); + TEST_RUN(basename, test_util_id_string); + TEST_RUN(basename, test_util_id_int); + TEST_RUN(basename, test_util_id_string_urn); + TEST_RUN(basename, test_util_id_int_urn); + + pkgconf_client_free(g_client); + + return EXIT_SUCCESS; +} diff --git a/contrib/pkgconf/tests/api/test-variable.c b/contrib/pkgconf/tests/api/test-variable.c index ec65df3ae5a8..c3c5b4a03283 100644 --- a/contrib/pkgconf/tests/api/test-variable.c +++ b/contrib/pkgconf/tests/api/test-variable.c @@ -200,6 +200,112 @@ test_variable_eval_str_chained(void) pkgconf_client_free(client); } +static void +test_variable_eval_name_plain(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + seed_variable(&vars, "version", "1.2.3"); + + char *out = pkgconf_variable_eval_name(client, &vars, "version"); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "1.2.3"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_variable_eval_name_with_reference(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + seed_variable(&vars, "prefix", "/opt/foo"); + seed_variable(&vars, "libdir", "${prefix}/lib"); + + char *out = pkgconf_variable_eval_name(client, &vars, "libdir"); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "/opt/foo/lib"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_variable_eval_name_absent(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + // Looking up a variable that was never defined yields no value. + char *out = pkgconf_variable_eval_name(client, &vars, "nonexistent"); + TEST_ASSERT_NULL(out); + + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_variable_eval_name_sysroot_prepended(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_client_set_sysroot_dir(client, "/sysroot"); + seed_variable(&vars, "libdir", "/opt/foo/lib"); + + // A plausible path that does not already begin with sysroot gets it prepended. + char *out = pkgconf_variable_eval_name(client, &vars, "libdir"); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "/sysroot/opt/foo/lib"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_variable_eval_name_sysroot_not_doubled(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_client_set_sysroot_dir(client, "/sysroot"); + seed_variable(&vars, "libdir", "/sysroot/opt/foo/lib"); + + // A value that already begins with sysroot must not have it prepended twice. + char *out = pkgconf_variable_eval_name(client, &vars, "libdir"); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "/sysroot/opt/foo/lib"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + +static void +test_variable_eval_name_non_path_no_sysroot(void) +{ + pkgconf_client_t *client = test_client_new(); + pkgconf_list_t vars = PKGCONF_LIST_INITIALIZER; + + pkgconf_client_set_sysroot_dir(client, "/sysroot"); + seed_variable(&vars, "version", "1.2.3"); + + // A non-path value is left untouched even when sysroot is set. + char *out = pkgconf_variable_eval_name(client, &vars, "version"); + TEST_ASSERT_NONNULL(out); + TEST_ASSERT_STRCMP_EQ(out, "1.2.3"); + + free(out); + pkgconf_variable_list_free(&vars); + pkgconf_client_free(client); +} + static void test_variable_list_free_handles_empty(void) { @@ -240,6 +346,12 @@ main(int argc, char *argv[]) TEST_RUN(basename, test_variable_eval_str_plain); TEST_RUN(basename, test_variable_eval_str_with_reference); TEST_RUN(basename, test_variable_eval_str_chained); + TEST_RUN(basename, test_variable_eval_name_plain); + TEST_RUN(basename, test_variable_eval_name_with_reference); + TEST_RUN(basename, test_variable_eval_name_absent); + TEST_RUN(basename, test_variable_eval_name_sysroot_prepended); + TEST_RUN(basename, test_variable_eval_name_sysroot_not_doubled); + TEST_RUN(basename, test_variable_eval_name_non_path_no_sysroot); TEST_RUN(basename, test_variable_list_free_handles_empty); TEST_RUN(basename, test_variable_list_free_handles_many); diff --git a/contrib/pkgconf/tests/lib-pccritic/nodesc.pc b/contrib/pkgconf/tests/lib-pccritic/nodesc.pc new file mode 100644 index 000000000000..d3146f790a22 --- /dev/null +++ b/contrib/pkgconf/tests/lib-pccritic/nodesc.pc @@ -0,0 +1,8 @@ +prefix=/test +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: nodesc +Version: 1.0.0 +Cflags: -I${includedir} +Libs: -L${libdir} -lnodesc diff --git a/contrib/pkgconf/tests/lib-pccritic/perfect.pc b/contrib/pkgconf/tests/lib-pccritic/perfect.pc new file mode 100644 index 000000000000..f44a4b757b07 --- /dev/null +++ b/contrib/pkgconf/tests/lib-pccritic/perfect.pc @@ -0,0 +1,14 @@ +prefix=/test +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: perfect +Description: A perfectly well-formed test package +Version: 1.0.0 +URL: https://example.org/perfect +Maintainer: Example Maintainer +Source: https://example.org/perfect-1.0.0.tar.gz +License: ISC +Cflags: -I${includedir} +Libs: -L${libdir} -lperfect diff --git a/contrib/pkgconf/tests/lib-pccritic/polluted.pc b/contrib/pkgconf/tests/lib-pccritic/polluted.pc new file mode 100644 index 000000000000..7079ca26af9f --- /dev/null +++ b/contrib/pkgconf/tests/lib-pccritic/polluted.pc @@ -0,0 +1,14 @@ +prefix=/test +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: polluted +Description: A package whose Cflags pollute consumer builds +Version: 1.0.0 +URL: https://example.org/polluted +Maintainer: Example Maintainer +Source: https://example.org/polluted-1.0.0.tar.gz +License: ISC +Cflags: -I${includedir} -O2 -g +Libs: -L${libdir} -lpolluted diff --git a/contrib/pkgconf/tests/lib-relocatable/abs-boundary/lib/pkgconfig/boundary.pc b/contrib/pkgconf/tests/lib-relocatable/abs-boundary/lib/pkgconfig/boundary.pc new file mode 100644 index 000000000000..f27e0332a037 --- /dev/null +++ b/contrib/pkgconf/tests/lib-relocatable/abs-boundary/lib/pkgconfig/boundary.pc @@ -0,0 +1,7 @@ +prefix=/nonexistent/hardcoded/ +includedir=/nonexistent/hardcoded/include +siblingdir=/nonexistent/hardcodedX + +Name: boundary +Description: trailing separator in prefix must still require a component boundary +Version: 1 diff --git a/contrib/pkgconf/tests/lib-relocatable/plain-prefix/lib/pkgconfig/plain.pc b/contrib/pkgconf/tests/lib-relocatable/plain-prefix/lib/pkgconfig/plain.pc new file mode 100644 index 000000000000..5e9d94c353fe --- /dev/null +++ b/contrib/pkgconf/tests/lib-relocatable/plain-prefix/lib/pkgconfig/plain.pc @@ -0,0 +1,6 @@ +prefix=/nonexistent/plain +includedir=/nonexistent/plain/include + +Name: plain +Description: prefix without a trailing separator still relocates correctly +Version: 1 diff --git a/contrib/pkgconf/tests/lib-relocatable/trailing-prefix/lib/pkgconfig/trailing.pc b/contrib/pkgconf/tests/lib-relocatable/trailing-prefix/lib/pkgconfig/trailing.pc new file mode 100644 index 000000000000..09bf8b6b0ac4 --- /dev/null +++ b/contrib/pkgconf/tests/lib-relocatable/trailing-prefix/lib/pkgconfig/trailing.pc @@ -0,0 +1,7 @@ +prefix=${pcfiledir}/../../ +includedir=${pcfiledir}/../../include + +Name: trailing +Description: issue #577: prefix ending in a separator must not drop the join +Version: 1 +Cflags: -I${includedir} diff --git a/contrib/pkgconf/tests/lib-sbom-files/agent_name.json b/contrib/pkgconf/tests/lib-sbom-files/agent_name.json index 37694702a5bc..da828375ede9 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/agent_name.json +++ b/contrib/pkgconf/tests/lib-sbom-files/agent_name.json @@ -7,6 +7,12 @@ "spdxId": "https://github.com/pkgconf/pkgconf/Agent/myagent", "name": "MyAgent" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Tool/spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "https://github.com/pkgconf/pkgconf/Agent/myagent" ], + "createUsing": [ + "https://github.com/pkgconf/pkgconf/Tool/spdxtool" + ], "specVersion": "3.0.1" }, { @@ -51,9 +60,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/myagent" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/test3_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/test3_maintainer", "software_copyrightText": "Test3 copyright text", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", diff --git a/contrib/pkgconf/tests/lib-sbom-files/agent_name_space.json b/contrib/pkgconf/tests/lib-sbom-files/agent_name_space.json index c773ce8ed5f4..83f593f7a104 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/agent_name_space.json +++ b/contrib/pkgconf/tests/lib-sbom-files/agent_name_space.json @@ -7,6 +7,12 @@ "spdxId": "https://github.com/pkgconf/pkgconf/Agent/my_agent", "name": "My Agent" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Tool/spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "https://github.com/pkgconf/pkgconf/Agent/my_agent" ], + "createUsing": [ + "https://github.com/pkgconf/pkgconf/Tool/spdxtool" + ], "specVersion": "3.0.1" }, { @@ -51,9 +60,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/my_agent" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/test3_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/test3_maintainer", "software_copyrightText": "Test3 copyright text", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", diff --git a/contrib/pkgconf/tests/lib-sbom-files/basic-spdx-base-id.json b/contrib/pkgconf/tests/lib-sbom-files/basic-spdx-base-id.json index 6271c947609f..3e87e0353b45 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/basic-spdx-base-id.json +++ b/contrib/pkgconf/tests/lib-sbom-files/basic-spdx-base-id.json @@ -7,6 +7,12 @@ "spdxId": "https://distfiles.ariadne.space/pkgconf/Agent/default", "name": "Default" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://distfiles.ariadne.space/pkgconf/Tool/spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "https://distfiles.ariadne.space/pkgconf/Agent/default" ], + "createUsing": [ + "https://distfiles.ariadne.space/pkgconf/Tool/spdxtool" + ], "specVersion": "3.0.1" }, { @@ -51,9 +60,7 @@ "originatedBy": [ "https://distfiles.ariadne.space/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://distfiles.ariadne.space/pkgconf/Agent/test3_maintainer" - ], + "suppliedBy": "https://distfiles.ariadne.space/pkgconf/Agent/test3_maintainer", "software_copyrightText": "Test3 copyright text", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", diff --git a/contrib/pkgconf/tests/lib-sbom-files/basic-use-uri.json b/contrib/pkgconf/tests/lib-sbom-files/basic-use-uri.json index 338493050545..748a47e3b51c 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/basic-use-uri.json +++ b/contrib/pkgconf/tests/lib-sbom-files/basic-use-uri.json @@ -7,6 +7,12 @@ "spdxId": "github.com:pkgconf:pkgconf:Agent:default", "name": "Default" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "github.com:pkgconf:pkgconf:Tool:spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "github.com:pkgconf:pkgconf:Agent:default" ], + "createUsing": [ + "github.com:pkgconf:pkgconf:Tool:spdxtool" + ], "specVersion": "3.0.1" }, { @@ -51,9 +60,7 @@ "originatedBy": [ "github.com:pkgconf:pkgconf:Agent:default" ], - "suppliedBy": [ - "github.com:pkgconf:pkgconf:Agent:test3_maintainer" - ], + "suppliedBy": "github.com:pkgconf:pkgconf:Agent:test3_maintainer", "software_copyrightText": "Test3 copyright text", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", diff --git a/contrib/pkgconf/tests/lib-sbom-files/basic.json b/contrib/pkgconf/tests/lib-sbom-files/basic.json index b924b0317604..499929e2ba41 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/basic.json +++ b/contrib/pkgconf/tests/lib-sbom-files/basic.json @@ -7,6 +7,12 @@ "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", "name": "Default" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Tool/spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], + "createUsing": [ + "https://github.com/pkgconf/pkgconf/Tool/spdxtool" + ], "specVersion": "3.0.1" }, { @@ -51,9 +60,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/test3_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/test3_maintainer", "software_copyrightText": "Test3 copyright text", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", diff --git a/contrib/pkgconf/tests/lib-sbom-files/bomtool-basic.txt b/contrib/pkgconf/tests/lib-sbom-files/bomtool-basic.txt index 6c1fa22e8a6c..4ceec425bc90 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/bomtool-basic.txt +++ b/contrib/pkgconf/tests/lib-sbom-files/bomtool-basic.txt @@ -12,7 +12,6 @@ Created: test PackageName: test3@3.0.0 SPDXID: SPDXRef-Package-test3C403.0.0 PackageVersion: 3.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Test3 Maintainer PackageHomePage: https://github.com/pkgconf/pkgconf/ PackageLicenseDeclared: BSD-4-Clause diff --git a/contrib/pkgconf/tests/lib-sbom-files/bomtool-define_variable.txt b/contrib/pkgconf/tests/lib-sbom-files/bomtool-define_variable.txt index 13fa3a04a042..a040014e6d0b 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/bomtool-define_variable.txt +++ b/contrib/pkgconf/tests/lib-sbom-files/bomtool-define_variable.txt @@ -12,7 +12,6 @@ Created: test PackageName: variable-test1@1.0-123 SPDXID: SPDXRef-Package-variable-test1C401.0-123 PackageVersion: 1.0-123 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Variabletest1 Maintainer PackageHomePage: https://github.com/pkgconf/pkgconf/releases/ PackageLicenseDeclared: BSD-2-Clause diff --git a/contrib/pkgconf/tests/lib-sbom-files/bomtool-define_variable_with_dependency.txt b/contrib/pkgconf/tests/lib-sbom-files/bomtool-define_variable_with_dependency.txt index 6ced6ec3e758..5e8034cb1b41 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/bomtool-define_variable_with_dependency.txt +++ b/contrib/pkgconf/tests/lib-sbom-files/bomtool-define_variable_with_dependency.txt @@ -12,7 +12,6 @@ Created: test PackageName: variable-test2@2.0 SPDXID: SPDXRef-Package-variable-test2C402.0 PackageVersion: 2.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Variabletest2 Maintainer PackageHomePage: https://github.com/pkgconf/pkgconf/releases/ PackageLicenseDeclared: MIT @@ -27,7 +26,6 @@ PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pk PackageName: variable-test1@1.0-123 SPDXID: SPDXRef-Package-variable-test1C401.0-123 PackageVersion: 1.0-123 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Variabletest1 Maintainer PackageHomePage: https://github.com/pkgconf/pkgconf/releases/ PackageLicenseDeclared: BSD-2-Clause diff --git a/contrib/pkgconf/tests/lib-sbom-files/bomtool-meta_package.txt b/contrib/pkgconf/tests/lib-sbom-files/bomtool-meta_package.txt index 0a24d37c0695..ee6910da1199 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/bomtool-meta_package.txt +++ b/contrib/pkgconf/tests/lib-sbom-files/bomtool-meta_package.txt @@ -12,7 +12,6 @@ Created: test PackageName: meta_package@1.0.0 SPDXID: SPDXRef-Package-metaC5fpackageC401.0.0 PackageVersion: 1.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Meta Maintainer PackageHomePage: https://github.com/pkgconf/pkgconf PackageLicenseDeclared: BSD-2-Clause @@ -27,7 +26,6 @@ PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pk PackageName: test1@1.0.0 SPDXID: SPDXRef-Package-test1C401.0.0 PackageVersion: 1.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Test1 Maintainer PackageLicenseDeclared: BSD-1-Clause PackageLicenseConcluded: NOASSERTION @@ -41,7 +39,6 @@ PackageDownloadLocation: NOASSERTION PackageName: test2@2.0.0 SPDXID: SPDXRef-Package-test2C402.0.0 PackageVersion: 2.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Test2 Maintainer PackageHomePage: https://github.com/pkgconf/pkgconf/ PackageLicenseDeclared: BSD-2-Clause @@ -56,7 +53,6 @@ PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pk PackageName: test3@3.0.0 SPDXID: SPDXRef-Package-test3C403.0.0 PackageVersion: 3.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Test3 Maintainer PackageHomePage: https://github.com/pkgconf/pkgconf/ PackageLicenseDeclared: BSD-4-Clause @@ -71,7 +67,6 @@ PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pk PackageName: test4@4.0.0 SPDXID: SPDXRef-Package-test4C404.0.0 PackageVersion: 4.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Test4 Maintainer PackageHomePage: https://github.com/pkgconf/pkgconf/ PackageLicenseDeclared: MIT @@ -86,7 +81,6 @@ PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pk PackageName: test5@5.0.0 SPDXID: SPDXRef-Package-test5C405.0.0 PackageVersion: 5.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Test5 Maintainer PackageHomePage: https://github.com/pkgconf/pkgconf/ PackageLicenseDeclared: MIT @@ -101,7 +95,6 @@ PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pk PackageName: test6@6.0.0 SPDXID: SPDXRef-Package-test6C406.0.0 PackageVersion: 6.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Test6 Maintainer PackageHomePage: https://github.com/pkgconf/pkgconf/releases/ PackageLicenseDeclared: Apache-2.0 diff --git a/contrib/pkgconf/tests/lib-sbom-files/bomtool-multiple_packages.txt b/contrib/pkgconf/tests/lib-sbom-files/bomtool-multiple_packages.txt index 2637e3ee3076..1dcd4a55316f 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/bomtool-multiple_packages.txt +++ b/contrib/pkgconf/tests/lib-sbom-files/bomtool-multiple_packages.txt @@ -12,7 +12,6 @@ Created: test PackageName: test5@5.0.0 SPDXID: SPDXRef-Package-test5C405.0.0 PackageVersion: 5.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Test5 Maintainer PackageHomePage: https://github.com/pkgconf/pkgconf/ PackageLicenseDeclared: MIT @@ -27,7 +26,6 @@ PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pk PackageName: test6@6.0.0 SPDXID: SPDXRef-Package-test6C406.0.0 PackageVersion: 6.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Test6 Maintainer PackageHomePage: https://github.com/pkgconf/pkgconf/releases/ PackageLicenseDeclared: Apache-2.0 diff --git a/contrib/pkgconf/tests/lib-sbom-files/bomtool-nolicense.txt b/contrib/pkgconf/tests/lib-sbom-files/bomtool-nolicense.txt index d79fa8c4345c..21b8351dbea5 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/bomtool-nolicense.txt +++ b/contrib/pkgconf/tests/lib-sbom-files/bomtool-nolicense.txt @@ -12,7 +12,6 @@ Created: test PackageName: nolicense@1.0.0 SPDXID: SPDXRef-Package-nolicenseC401.0.0 PackageVersion: 1.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Nolicense Maintainer PackageHomePage: https://example.com/nolicense PackageLicenseDeclared: NOASSERTION diff --git a/contrib/pkgconf/tests/lib-sbom-files/bomtool-private_dependency.txt b/contrib/pkgconf/tests/lib-sbom-files/bomtool-private_dependency.txt index a9657ee553f9..233888a7f9b7 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/bomtool-private_dependency.txt +++ b/contrib/pkgconf/tests/lib-sbom-files/bomtool-private_dependency.txt @@ -12,7 +12,6 @@ Created: test PackageName: priv-parent@1.0.0 SPDXID: SPDXRef-Package-priv-parentC401.0.0 PackageVersion: 1.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Privparent Maintainer PackageHomePage: https://example.com/priv-parent PackageLicenseDeclared: MIT @@ -27,7 +26,6 @@ PackageDownloadLocation: NOASSERTION PackageName: priv-child@1.0.0 SPDXID: SPDXRef-Package-priv-childC401.0.0 PackageVersion: 1.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Privchild Maintainer PackageHomePage: https://example.com/priv-child PackageLicenseDeclared: MIT diff --git a/contrib/pkgconf/tests/lib-sbom-files/bomtool-special.txt b/contrib/pkgconf/tests/lib-sbom-files/bomtool-special.txt index 3cabf2da4fe4..dbf443fe4936 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/bomtool-special.txt +++ b/contrib/pkgconf/tests/lib-sbom-files/bomtool-special.txt @@ -12,7 +12,6 @@ Created: test PackageName: special@1.0.0 SPDXID: SPDXRef-Package-specialC401.0.0 PackageVersion: 1.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Special Maintainer PackageHomePage: https://example.com/special PackageLicenseDeclared: MIT diff --git a/contrib/pkgconf/tests/lib-sbom-files/bomtool-with_dependency.txt b/contrib/pkgconf/tests/lib-sbom-files/bomtool-with_dependency.txt index e74f6c398104..6111d26c4bdb 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/bomtool-with_dependency.txt +++ b/contrib/pkgconf/tests/lib-sbom-files/bomtool-with_dependency.txt @@ -12,7 +12,6 @@ Created: test PackageName: test2@2.0.0 SPDXID: SPDXRef-Package-test2C402.0.0 PackageVersion: 2.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Test2 Maintainer PackageHomePage: https://github.com/pkgconf/pkgconf/ PackageLicenseDeclared: BSD-2-Clause @@ -27,7 +26,6 @@ PackageDownloadLocation: https://github.com/pkgconf/pkgconf/archive/refs/tags/pk PackageName: test3@3.0.0 SPDXID: SPDXRef-Package-test3C403.0.0 PackageVersion: 3.0.0 -PackageDownloadLocation: NOASSERTION PackageSupplier: Person: Test3 Maintainer PackageHomePage: https://github.com/pkgconf/pkgconf/ PackageLicenseDeclared: BSD-4-Clause diff --git a/contrib/pkgconf/tests/lib-sbom-files/creation_id.json b/contrib/pkgconf/tests/lib-sbom-files/creation_id.json index ef09de67cba9..f3b11f7d5f24 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/creation_id.json +++ b/contrib/pkgconf/tests/lib-sbom-files/creation_id.json @@ -7,6 +7,12 @@ "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", "name": "Default" }, + { + "type": "Tool", + "creationInfo": "_:custom_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Tool/spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:custom_1", @@ -14,6 +20,9 @@ "createdBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], + "createUsing": [ + "https://github.com/pkgconf/pkgconf/Tool/spdxtool" + ], "specVersion": "3.0.1" }, { @@ -51,9 +60,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/test3_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/test3_maintainer", "software_copyrightText": "Test3 copyright text", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", diff --git a/contrib/pkgconf/tests/lib-sbom-files/define_variable.json b/contrib/pkgconf/tests/lib-sbom-files/define_variable.json index d97d0080fed4..64338a4db268 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/define_variable.json +++ b/contrib/pkgconf/tests/lib-sbom-files/define_variable.json @@ -7,6 +7,12 @@ "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", "name": "Default" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Tool/spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], + "createUsing": [ + "https://github.com/pkgconf/pkgconf/Tool/spdxtool" + ], "specVersion": "3.0.1" }, { @@ -51,9 +60,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/variabletest1_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/variabletest1_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf/releases/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", diff --git a/contrib/pkgconf/tests/lib-sbom-files/define_variable_with_dependency.json b/contrib/pkgconf/tests/lib-sbom-files/define_variable_with_dependency.json index 1aa4d8495c41..7eb433e399d7 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/define_variable_with_dependency.json +++ b/contrib/pkgconf/tests/lib-sbom-files/define_variable_with_dependency.json @@ -7,6 +7,12 @@ "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", "name": "Default" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Tool/spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], + "createUsing": [ + "https://github.com/pkgconf/pkgconf/Tool/spdxtool" + ], "specVersion": "3.0.1" }, { @@ -79,9 +88,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/variabletest2_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/variabletest2_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf/releases/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", @@ -95,9 +102,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/variabletest1_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/variabletest1_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf/releases/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", diff --git a/contrib/pkgconf/tests/lib-sbom-files/meta_package-use-uri-spdx-base-id.json b/contrib/pkgconf/tests/lib-sbom-files/meta_package-use-uri-spdx-base-id.json index b21e316c6a14..42768895f95b 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/meta_package-use-uri-spdx-base-id.json +++ b/contrib/pkgconf/tests/lib-sbom-files/meta_package-use-uri-spdx-base-id.json @@ -7,6 +7,12 @@ "spdxId": "distfiles.ariadne.space:pkgconf:Agent:default", "name": "Default" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "distfiles.ariadne.space:pkgconf:Tool:spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "distfiles.ariadne.space:pkgconf:Agent:default" ], + "createUsing": [ + "distfiles.ariadne.space:pkgconf:Tool:spdxtool" + ], "specVersion": "3.0.1" }, { @@ -210,9 +219,7 @@ "originatedBy": [ "distfiles.ariadne.space:pkgconf:Agent:default" ], - "suppliedBy": [ - "distfiles.ariadne.space:pkgconf:Agent:meta_maintainer" - ], + "suppliedBy": "distfiles.ariadne.space:pkgconf:Agent:meta_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", @@ -226,9 +233,7 @@ "originatedBy": [ "distfiles.ariadne.space:pkgconf:Agent:default" ], - "suppliedBy": [ - "distfiles.ariadne.space:pkgconf:Agent:test1_maintainer" - ], + "suppliedBy": "distfiles.ariadne.space:pkgconf:Agent:test1_maintainer", "software_copyrightText": "Test1 copyright text", "software_homePage": "", "software_downloadLocation": "", @@ -242,9 +247,7 @@ "originatedBy": [ "distfiles.ariadne.space:pkgconf:Agent:default" ], - "suppliedBy": [ - "distfiles.ariadne.space:pkgconf:Agent:test2_maintainer" - ], + "suppliedBy": "distfiles.ariadne.space:pkgconf:Agent:test2_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", @@ -258,9 +261,7 @@ "originatedBy": [ "distfiles.ariadne.space:pkgconf:Agent:default" ], - "suppliedBy": [ - "distfiles.ariadne.space:pkgconf:Agent:test3_maintainer" - ], + "suppliedBy": "distfiles.ariadne.space:pkgconf:Agent:test3_maintainer", "software_copyrightText": "Test3 copyright text", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", @@ -274,9 +275,7 @@ "originatedBy": [ "distfiles.ariadne.space:pkgconf:Agent:default" ], - "suppliedBy": [ - "distfiles.ariadne.space:pkgconf:Agent:test4_maintainer" - ], + "suppliedBy": "distfiles.ariadne.space:pkgconf:Agent:test4_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", @@ -290,9 +289,7 @@ "originatedBy": [ "distfiles.ariadne.space:pkgconf:Agent:default" ], - "suppliedBy": [ - "distfiles.ariadne.space:pkgconf:Agent:test5_maintainer" - ], + "suppliedBy": "distfiles.ariadne.space:pkgconf:Agent:test5_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", @@ -306,9 +303,7 @@ "originatedBy": [ "distfiles.ariadne.space:pkgconf:Agent:default" ], - "suppliedBy": [ - "distfiles.ariadne.space:pkgconf:Agent:test6_maintainer" - ], + "suppliedBy": "distfiles.ariadne.space:pkgconf:Agent:test6_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf/releases/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", diff --git a/contrib/pkgconf/tests/lib-sbom-files/meta_package.json b/contrib/pkgconf/tests/lib-sbom-files/meta_package.json index d033211f40cb..9e17c9cf87b0 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/meta_package.json +++ b/contrib/pkgconf/tests/lib-sbom-files/meta_package.json @@ -7,6 +7,12 @@ "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", "name": "Default" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Tool/spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], + "createUsing": [ + "https://github.com/pkgconf/pkgconf/Tool/spdxtool" + ], "specVersion": "3.0.1" }, { @@ -210,9 +219,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/meta_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/meta_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", @@ -226,9 +233,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/test1_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/test1_maintainer", "software_copyrightText": "Test1 copyright text", "software_homePage": "", "software_downloadLocation": "", @@ -242,9 +247,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/test2_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/test2_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", @@ -258,9 +261,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/test3_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/test3_maintainer", "software_copyrightText": "Test3 copyright text", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", @@ -274,9 +275,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/test4_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/test4_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", @@ -290,9 +289,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/test5_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/test5_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", @@ -306,9 +303,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/test6_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/test6_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf/releases/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", diff --git a/contrib/pkgconf/tests/lib-sbom-files/multi_copyright.json b/contrib/pkgconf/tests/lib-sbom-files/multi_copyright.json index 651ca80deb3d..a61b80f2d977 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/multi_copyright.json +++ b/contrib/pkgconf/tests/lib-sbom-files/multi_copyright.json @@ -7,6 +7,12 @@ "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", "name": "Default" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Tool/spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], + "createUsing": [ + "https://github.com/pkgconf/pkgconf/Tool/spdxtool" + ], "specVersion": "3.0.1" }, { @@ -51,9 +60,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/mc_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/mc_maintainer", "software_copyrightText": "First copyright holder\nSecond copyright holder", "software_homePage": "https://example.com/mc", "software_downloadLocation": "", diff --git a/contrib/pkgconf/tests/lib-sbom-files/multiple_packages.json b/contrib/pkgconf/tests/lib-sbom-files/multiple_packages.json index 62cb4d4f68a5..0229d141b799 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/multiple_packages.json +++ b/contrib/pkgconf/tests/lib-sbom-files/multiple_packages.json @@ -7,6 +7,12 @@ "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", "name": "Default" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Tool/spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], + "createUsing": [ + "https://github.com/pkgconf/pkgconf/Tool/spdxtool" + ], "specVersion": "3.0.1" }, { @@ -78,9 +87,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/test5_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/test5_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", @@ -94,9 +101,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/test6_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/test6_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf/releases/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", diff --git a/contrib/pkgconf/tests/lib-sbom-files/nolicense.json b/contrib/pkgconf/tests/lib-sbom-files/nolicense.json index e45dd5c2299f..adbb2fd3ab73 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/nolicense.json +++ b/contrib/pkgconf/tests/lib-sbom-files/nolicense.json @@ -7,6 +7,12 @@ "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", "name": "Default" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Tool/spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], + "createUsing": [ + "https://github.com/pkgconf/pkgconf/Tool/spdxtool" + ], "specVersion": "3.0.1" }, { @@ -43,9 +52,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/nolicense_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/nolicense_maintainer", "software_copyrightText": "Nolicense copyright text", "software_homePage": "https://example.com/nolicense", "software_downloadLocation": "https://example.com/nolicense/nolicense-1.0.0.tar.gz", diff --git a/contrib/pkgconf/tests/lib-sbom-files/private_dependency.json b/contrib/pkgconf/tests/lib-sbom-files/private_dependency.json index c824794183f7..76ac9bb30188 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/private_dependency.json +++ b/contrib/pkgconf/tests/lib-sbom-files/private_dependency.json @@ -7,6 +7,12 @@ "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", "name": "Default" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Tool/spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], + "createUsing": [ + "https://github.com/pkgconf/pkgconf/Tool/spdxtool" + ], "specVersion": "3.0.1" }, { @@ -73,9 +82,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/privparent_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/privparent_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://example.com/priv-parent", "software_downloadLocation": "", @@ -89,9 +96,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/privchild_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/privchild_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://example.com/priv-child", "software_downloadLocation": "", diff --git a/contrib/pkgconf/tests/lib-sbom-files/special.json b/contrib/pkgconf/tests/lib-sbom-files/special.json index 3d4fa7abae69..f0925144544e 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/special.json +++ b/contrib/pkgconf/tests/lib-sbom-files/special.json @@ -7,6 +7,12 @@ "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", "name": "Default" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Tool/spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], + "createUsing": [ + "https://github.com/pkgconf/pkgconf/Tool/spdxtool" + ], "specVersion": "3.0.1" }, { @@ -51,9 +60,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/special_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/special_maintainer", "software_copyrightText": "Quote \" backslash \\ and\ttab", "software_homePage": "https://example.com/special", "software_downloadLocation": "", diff --git a/contrib/pkgconf/tests/lib-sbom-files/with_dependency.json b/contrib/pkgconf/tests/lib-sbom-files/with_dependency.json index 583fd5a6d81b..b376e9a819f7 100644 --- a/contrib/pkgconf/tests/lib-sbom-files/with_dependency.json +++ b/contrib/pkgconf/tests/lib-sbom-files/with_dependency.json @@ -7,6 +7,12 @@ "spdxId": "https://github.com/pkgconf/pkgconf/Agent/default", "name": "Default" }, + { + "type": "Tool", + "creationInfo": "_:creationinfo_1", + "spdxId": "https://github.com/pkgconf/pkgconf/Tool/spdxtool", + "name": "spdxtool" + }, { "type": "CreationInfo", "@id": "_:creationinfo_1", @@ -14,6 +20,9 @@ "createdBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], + "createUsing": [ + "https://github.com/pkgconf/pkgconf/Tool/spdxtool" + ], "specVersion": "3.0.1" }, { @@ -79,9 +88,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/test2_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/test2_maintainer", "software_copyrightText": "NOASSERTION", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", @@ -95,9 +102,7 @@ "originatedBy": [ "https://github.com/pkgconf/pkgconf/Agent/default" ], - "suppliedBy": [ - "https://github.com/pkgconf/pkgconf/Agent/test3_maintainer" - ], + "suppliedBy": "https://github.com/pkgconf/pkgconf/Agent/test3_maintainer", "software_copyrightText": "Test3 copyright text", "software_homePage": "https://github.com/pkgconf/pkgconf/", "software_downloadLocation": "https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-2.5.1.tar.gz", diff --git a/contrib/pkgconf/tests/lib1/depgraph-break.pc b/contrib/pkgconf/tests/lib1/depgraph-break.pc index 61e00cc62bc1..31235834caa4 100644 --- a/contrib/pkgconf/tests/lib1/depgraph-break.pc +++ b/contrib/pkgconf/tests/lib1/depgraph-break.pc @@ -9,4 +9,4 @@ Version: 1.2.3 Libs: -L${libdir} -lfoo Cflags: -fPIC -I${includedir}/foo Cflags.private: -DFOO_STATIC -Requires: nonexistant +Requires: nonexistent diff --git a/contrib/pkgconf/tests/lib1/escape-layers-bare-var.pc b/contrib/pkgconf/tests/lib1/escape-layers-bare-var.pc new file mode 100644 index 000000000000..b6588452b710 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/escape-layers-bare-var.pc @@ -0,0 +1,7 @@ +libs_list=-L/test/a\ dir -la -Wl,--foo\\bar + +Name: escape-layers-bare-var +Description: test fixture +Version: 1.0.0 + +Libs: ${libs_list} diff --git a/contrib/pkgconf/tests/lib1/escape-layers.pc b/contrib/pkgconf/tests/lib1/escape-layers.pc new file mode 100644 index 000000000000..18d72bf01d08 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/escape-layers.pc @@ -0,0 +1,13 @@ +prefix=/test/a\ dir +libdir=${prefix}/lib +backslash=x\\y +quoted_dq="item1 item2 item\ with\ spaces" +quoted_sq='item1 item2 item\ with\ spaces' +unquoted=item1 item2 item\ with\ spaces + +Name: escape-layers +Description: test fixture +Version: 1.0.0 + +Libs: -L${libdir} -L/test/lit\ eral -la +Cflags: -I${prefix} -DBS=${backslash} -DLIT=p\\q -DLITSP=p\ q diff --git a/contrib/pkgconf/tests/lib1/fragment-escaped-space-var.pc b/contrib/pkgconf/tests/lib1/fragment-escaped-space-var.pc new file mode 100644 index 000000000000..a9d677d21d20 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/fragment-escaped-space-var.pc @@ -0,0 +1,8 @@ +prefix=/test/a\ dir/b\ dir + +Name: fragment-escaped-space-var +Description: test fixture +Version: 1.0.0 + +Libs: -L${prefix} -la +Cflags: -I${prefix} diff --git a/contrib/pkgconf/tests/lib1/maxpkg-first.pc b/contrib/pkgconf/tests/lib1/maxpkg-first.pc new file mode 100644 index 000000000000..af1b406a91f3 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/maxpkg-first.pc @@ -0,0 +1,5 @@ +qux=first-value + +Name: maxpkg-first +Description: test fixture +Version: 1.0.0 diff --git a/contrib/pkgconf/tests/lib1/maxpkg-second.pc b/contrib/pkgconf/tests/lib1/maxpkg-second.pc new file mode 100644 index 000000000000..4cf8847f4be0 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/maxpkg-second.pc @@ -0,0 +1,6 @@ +qux=second-value +second_only=second-only-value + +Name: maxpkg-second +Description: test fixture +Version: 1.0.0 diff --git a/contrib/pkgconf/tests/lib1/self-referential-fragment.pc b/contrib/pkgconf/tests/lib1/self-referential-fragment.pc new file mode 100644 index 000000000000..017ccf774ef7 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/self-referential-fragment.pc @@ -0,0 +1,7 @@ +x=$${x} + +Name: self-referential-fragment +Description: test fixture +Version: 1.0.0 + +Cflags: ${x} diff --git a/contrib/pkgconf/tests/lib1/sysroot-inject-bare.pc b/contrib/pkgconf/tests/lib1/sysroot-inject-bare.pc new file mode 100644 index 000000000000..5d0e97b24f81 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/sysroot-inject-bare.pc @@ -0,0 +1,6 @@ +prefix=/usr +Cflags: -I${pc_sysrootdir} + +Name: sysroot-inject-bare +Description: test fixture +Version: 1.0.0 diff --git a/contrib/pkgconf/tests/lib1/sysroot-inject-explicit.pc b/contrib/pkgconf/tests/lib1/sysroot-inject-explicit.pc new file mode 100644 index 000000000000..6f650a05dc84 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/sysroot-inject-explicit.pc @@ -0,0 +1,7 @@ +prefix=/usr +Cflags: -I${pc_sysrootdir}/opt/x +Libs: -L${pc_sysrootdir}/opt/lib -lx + +Name: sysroot-inject-explicit +Description: test fixture +Version: 1.0.0 diff --git a/contrib/pkgconf/tests/lib1/sysroot-inject-hardcoded.pc b/contrib/pkgconf/tests/lib1/sysroot-inject-hardcoded.pc new file mode 100644 index 000000000000..91ccc6d5a2db --- /dev/null +++ b/contrib/pkgconf/tests/lib1/sysroot-inject-hardcoded.pc @@ -0,0 +1,7 @@ +prefix=/usr +Cflags: -I/opt/x +Libs: -L/opt/lib -lx + +Name: sysroot-inject-hardcoded +Description: test fixture +Version: 1.0.0 diff --git a/contrib/pkgconf/tests/lib1/sysroot-inject-isystem-attached.pc b/contrib/pkgconf/tests/lib1/sysroot-inject-isystem-attached.pc new file mode 100644 index 000000000000..d1635da83402 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/sysroot-inject-isystem-attached.pc @@ -0,0 +1,6 @@ +prefix=/usr +Cflags: -isystem/opt/x + +Name: sysroot-inject-isystem-attached +Description: test fixture +Version: 1.0.0 diff --git a/contrib/pkgconf/tests/lib1/sysroot-inject-isystem-explicit.pc b/contrib/pkgconf/tests/lib1/sysroot-inject-isystem-explicit.pc new file mode 100644 index 000000000000..189f8ca5d00b --- /dev/null +++ b/contrib/pkgconf/tests/lib1/sysroot-inject-isystem-explicit.pc @@ -0,0 +1,6 @@ +prefix=/usr +Cflags: -isystem${pc_sysrootdir}/opt/x + +Name: sysroot-inject-isystem-explicit +Description: test fixture +Version: 1.0.0 diff --git a/contrib/pkgconf/tests/lib1/sysroot-inject-isystem-literal.pc b/contrib/pkgconf/tests/lib1/sysroot-inject-isystem-literal.pc new file mode 100644 index 000000000000..f3ec0f3ed81a --- /dev/null +++ b/contrib/pkgconf/tests/lib1/sysroot-inject-isystem-literal.pc @@ -0,0 +1,6 @@ +prefix=/usr +Cflags: -isystem/sysroot/opt/x + +Name: sysroot-inject-isystem-literal +Description: test fixture +Version: 1.0.0 diff --git a/contrib/pkgconf/tests/lib1/sysroot-inject-isystem-separate.pc b/contrib/pkgconf/tests/lib1/sysroot-inject-isystem-separate.pc new file mode 100644 index 000000000000..dff1860f3a81 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/sysroot-inject-isystem-separate.pc @@ -0,0 +1,6 @@ +prefix=/usr +Cflags: -isystem /opt/x + +Name: sysroot-inject-isystem-separate +Description: test fixture +Version: 1.0.0 diff --git a/contrib/pkgconf/tests/lib1/sysroot-inject-literal.pc b/contrib/pkgconf/tests/lib1/sysroot-inject-literal.pc new file mode 100644 index 000000000000..9cc6622dfed8 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/sysroot-inject-literal.pc @@ -0,0 +1,6 @@ +prefix=/usr +Cflags: -I/sysroot/opt/x + +Name: sysroot-inject-literal +Description: test fixture +Version: 1.0.0 diff --git a/contrib/pkgconf/tests/lib1/sysroot-inject-mixed.pc b/contrib/pkgconf/tests/lib1/sysroot-inject-mixed.pc new file mode 100644 index 000000000000..4bcc90e37c64 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/sysroot-inject-mixed.pc @@ -0,0 +1,6 @@ +prefix=/usr +Cflags: -I${pc_sysrootdir}/a -I/b + +Name: sysroot-inject-mixed +Description: test fixture +Version: 1.0.0 diff --git a/contrib/pkgconf/tests/lib1/sysroot-inject-multi-fragment.pc b/contrib/pkgconf/tests/lib1/sysroot-inject-multi-fragment.pc new file mode 100644 index 000000000000..6204074ed957 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/sysroot-inject-multi-fragment.pc @@ -0,0 +1,7 @@ +prefix=/usr +libs_list=-L${pc_sysrootdir}/a -L/b + +Name: sysroot-inject-multi-fragment +Description: test fixture +Version: 1.0.0 +Libs: ${libs_list} diff --git a/contrib/pkgconf/tests/lib1/sysroot-inject-prefix.pc b/contrib/pkgconf/tests/lib1/sysroot-inject-prefix.pc new file mode 100644 index 000000000000..b28c05ae9c15 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/sysroot-inject-prefix.pc @@ -0,0 +1,6 @@ +prefix=/usr +Cflags: -I${prefix}/include + +Name: sysroot-inject-prefix +Description: test fixture +Version: 1.0.0 diff --git a/contrib/pkgconf/tests/lib1/windows-sysroot-inject.pc b/contrib/pkgconf/tests/lib1/windows-sysroot-inject.pc new file mode 100644 index 000000000000..58915a274c3a --- /dev/null +++ b/contrib/pkgconf/tests/lib1/windows-sysroot-inject.pc @@ -0,0 +1,5 @@ +Name: windows-sysroot-inject +Description: regression test for issue #574 (sysroot injection normalized) +Version: 1 +Libs: -L/opt/lib -linject +Cflags: -I/opt/include diff --git a/contrib/pkgconf/tests/lib1/windows-sysroot-libdir.pc b/contrib/pkgconf/tests/lib1/windows-sysroot-libdir.pc new file mode 100644 index 000000000000..75e28d203683 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/windows-sysroot-libdir.pc @@ -0,0 +1,4 @@ +Name: windows-sysroot-libdir +Description: regression test for issue #574 +Version: 1 +Libs: -LC:/dir/install_dir/usr/local/lib -lproject diff --git a/contrib/pkgconf/tests/lib1/windows-system-libdir.pc b/contrib/pkgconf/tests/lib1/windows-system-libdir.pc new file mode 100644 index 000000000000..5fdd8a52bb55 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/windows-system-libdir.pc @@ -0,0 +1,4 @@ +Name: windows-system-libdir +Description: regression test for issue #574 (system libdir filtering separators) +Version: 1 +Libs: -LC:/sys/lib -lfoo diff --git a/contrib/pkgconf/tests/lib1/windows-top-builddir.pc b/contrib/pkgconf/tests/lib1/windows-top-builddir.pc new file mode 100644 index 000000000000..d9c848e88100 --- /dev/null +++ b/contrib/pkgconf/tests/lib1/windows-top-builddir.pc @@ -0,0 +1,4 @@ +Name: windows-top-builddir +Description: regression test for issue #574 (pc_top_builddir separators) +Version: 1 +Libs: -L${pc_top_builddir}/lib -ltbd diff --git a/contrib/pkgconf/tests/test-runner.c b/contrib/pkgconf/tests/test-runner.c index 85a63df6c810..33c8feb110b8 100644 --- a/contrib/pkgconf/tests/test-runner.c +++ b/contrib/pkgconf/tests/test-runner.c @@ -181,7 +181,7 @@ environ_lookup_handler(const pkgconf_client_t *client, const char *key) if (!strcmp(key, env->key)) { - char cwd[PATH_MAX] = {0}; + char cwd[PKGCONF_ITEM_SIZE] = {0}; const char *pwd = getcwd(cwd, sizeof(cwd)); pkgconf_buffer_t expanded = PKGCONF_BUFFER_INITIALIZER; @@ -883,7 +883,7 @@ run_tool(const pkgconf_test_case_t *testcase, pkgconf_buffer_t *o_stdout, pkgcon } // Inject Environment vars for the child process - char tool_cwd[PATH_MAX] = {0}; + char tool_cwd[PKGCONF_ITEM_SIZE] = {0}; const char *pwd = getcwd(tool_cwd, sizeof(tool_cwd)); pkgconf_node_t *iter; @@ -1195,7 +1195,7 @@ run_test_case(const pkgconf_test_case_t *testcase) } // If the test has setup steps, create a new tmp_dir and chdir into it. - char original_cwd[PATH_MAX] = {0}; + char original_cwd[PKGCONF_ITEM_SIZE] = {0}; char *tmp_dir = NULL; if (getcwd(original_cwd, sizeof(original_cwd)) == NULL) @@ -1258,7 +1258,13 @@ run_test_case(const pkgconf_test_case_t *testcase) .testcase = testcase, }; - pkgconf_client_init(&state.cli_state.pkg_client, error_handler, NULL, personality, &state, environ_lookup_handler); + pkgconf_client_options_t client_options = { + .error_handler = error_handler, + .personality = personality, + .client_data = &state, + .environ_lookup_handler = environ_lookup_handler, + }; + pkgconf_client_init_with_options(&state.cli_state.pkg_client, &client_options); pkgconf_client_set_output(&state.cli_state.pkg_client, &out->output); pkgconf_node_t *iter; @@ -1272,7 +1278,7 @@ run_test_case(const pkgconf_test_case_t *testcase) * Re-expand Query now that %PWD% is known (if we have a tmp_dir). * For tests without a tmp_dir this is a no-op since %PWD% won't appear. */ - char query_cwd[PATH_MAX] = {0}; + char query_cwd[PKGCONF_ITEM_SIZE] = {0}; const char *query_pwd = getcwd(query_cwd, sizeof(query_cwd)); pkgconf_buffer_t query_expanded = PKGCONF_BUFFER_INITIALIZER; @@ -1314,7 +1320,7 @@ run_test_case(const pkgconf_test_case_t *testcase) { pkgconf_bufferset_t *set = iter->data; - char expected_cwd[PATH_MAX] = {0}; + char expected_cwd[PKGCONF_ITEM_SIZE] = {0}; const char *expected_pwd = getcwd(expected_cwd, sizeof(expected_cwd)); pkgconf_buffer_t expected_expanded = PKGCONF_BUFFER_INITIALIZER; @@ -1559,7 +1565,7 @@ main(int argc, char *argv[]) usage(); { - char test_fixtures_dir_abs[PATH_MAX] = {0}; + char test_fixtures_dir_abs[PKGCONF_ITEM_SIZE] = {0}; if (!realpath(test_fixtures_dir_arg, test_fixtures_dir_abs)) { fprintf(stderr, "realpath failed: %s\n", strerror(errno)); diff --git a/contrib/pkgconf/tests/win-shim.h b/contrib/pkgconf/tests/win-shim.h index d870d96fc284..76f3867bbcc7 100644 --- a/contrib/pkgconf/tests/win-shim.h +++ b/contrib/pkgconf/tests/win-shim.h @@ -20,6 +20,8 @@ #ifdef _WIN32 +#include + #include #include #include @@ -44,6 +46,17 @@ # define popen _popen # define pclose _pclose +static inline int +mkstemp(char *tmpl) +{ + if (_mktemp_s(tmpl, strlen(tmpl) + 1) != 0) + return -1; + return _open(tmpl, _O_CREAT | _O_EXCL | _O_RDWR | _O_BINARY, _S_IREAD | _S_IWRITE); +} +#endif // _MSC_VER + +#if !HAVE_DECL_MKDTEMP + static inline char * mkdtemp(char *tmpl) { @@ -54,14 +67,7 @@ mkdtemp(char *tmpl) return tmpl; } -static inline int -mkstemp(char *tmpl) -{ - if (_mktemp_s(tmpl, strlen(tmpl) + 1) != 0) - return -1; - return _open(tmpl, _O_CREAT | _O_EXCL | _O_RDWR | _O_BINARY, _S_IREAD | _S_IWRITE); -} -#endif // _MSC_VER +#endif // !HAVE_DECL_MKDTEMP #endif // _WIN32 #endif // WIN_SHIM_H diff --git a/lib/libpkgconf/libpkgconf/config.h b/lib/libpkgconf/libpkgconf/config.h index 2da1b4796e9d..af295fd29f0b 100644 --- a/lib/libpkgconf/libpkgconf/config.h +++ b/lib/libpkgconf/libpkgconf/config.h @@ -1,6 +1,14 @@ /* libpkgconf/config.h. Generated from config.h.in by configure. */ /* libpkgconf/config.h.in. Generated from configure.ac by autoheader. */ +/* Define to 1 if you have the declaration of 'getc_unlocked', and to 0 if you + don't. */ +#define HAVE_DECL_GETC_UNLOCKED 1 + +/* Define to 1 if you have the declaration of 'mkdtemp', and to 0 if you + don't. */ +#define HAVE_DECL_MKDTEMP 1 + /* Define to 1 if you have the declaration of 'nl_langinfo_l', and to 0 if you don't. */ #define HAVE_DECL_NL_LANGINFO_L 1 @@ -68,16 +76,16 @@ #define PACKAGE_NAME "pkgconf" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "pkgconf 2.9.93" +#define PACKAGE_STRING "pkgconf 3.0.9" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "pkgconf" /* Define to the home page for this package. */ -#define PACKAGE_URL "" +#define PACKAGE_URL "https://github.com/pkgconf/pkgconf" /* Define to the version of this package. */ -#define PACKAGE_VERSION "2.9.93" +#define PACKAGE_VERSION "3.0.9" /* Define to 1 if all of the C89 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for @@ -85,7 +93,7 @@ #define STDC_HEADERS 1 /* Version number of package */ -#define VERSION "2.9.93" +#define VERSION "3.0.9" /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */