C++ guarantees static initializers run in a thread-safe manner,
move the confdir initialization to a constructor of a tiny object
and voila we don't need the pthread once dance.
On entry to rpmlog() we compare the log mask to see if it's something
we need to act on at all. Since we've been using rpmlogSetMask() for
this, each and every RPMLOG_DEBUG etc call that is not normally logged
stops on its way to take at least one read mutex to do nothing at all.
Which is nuts.
rpmlogSetMask() technically does need the mutex lock because it both reads
and writes, and something could come in between. But for the rpmlog() entry
we only need to read, and reading an int is atomic. Add an internal
helper that lets us get the silly mask without locking.
See previous commits for rationale. Of particular note here is that
we now always take a write lock where we previously dynamically selected
between read/write, because the STL primitives don't seem to support
that in any easy way.
Replace manual pthread_* calls with the STL counterparts. Since there
was nothing to wrap these calls to begin with, this makes for a
particularly nice cleanup.
Shared and exclusive locks are of different types in STL so we can't
easily return one or the other from poolLock() as per the write
argument. Just convert all poolLock() calls sites to name their
lock type locally.
C++ guarantees initialization of static objects takes place before
threads can run, so we don't need all the locksInitialized fubar.
The native objects also release themselves which fixes a theoretical
leak we had: we never destroyed the lock or lockattr so they remained
reachable until program exit.
We could continue to acquire and release the lock in the corresponding
functions but that's not RAII and would be inconsistent with what we
do elsewhere in rpm, just convert to the local lock variable style.
Issuing deprecation warnings on packages built long time ago is
just antisocial behavior when the user is powerless to do anything
about it.
When running scripts, pass the builder rpm version to Lua through the
registry, and filter out the warnings when the package was built with
an rpm version where these functions were not yet deprecated.
Usage through rpmlua and macros always gets warnings: those are things
that can technically be fixed by the user.
Commit 46bd0ed2a9 did document
rpm.redirect2null() as deprecated but failed to add an actual warning
on it. Meaning no existing user will notice it being deprecated,
unless they were also using some of the other deprecated items too.
Turn check_deprecated() into an actual function for better control,
we'll have use for that later on.
The status returned from waitpid() is not your exit code, it's encoded
and needs processing the W*() macros, like we do in the new rpm.spawn()
function.
These two should really be refactored to use common code, but leaving
that to later because one is in C and the other one in C++...
Turns out real-world usage needs more control than rpm.execute()
delivers. This could be crammed into rpm.execute() but it'd be forward
incompatible in a somewhat non-obvious way, we might just as well
add a separate function for it.
Supports redirecting stdin, stdout and stderr to a given path, support
for file descriptors, other actions and spawn attributes can be added
later.
Fixes: #3192
Reset the Lua stack on return from rpmluaRunScript() to discard any
unhandled returned data from the scriptlet. This may happen if there's
eg "return 0" from a non-macro scriptlet.
We could check for a numeric return value here and treat it as an exit
code, but then what to do with other kinds of returned data?
Our documentation states errors in Lua scriptlets should be signaled with
Lua error() function, it seems better to stick with that and avoid
introducing ambiguities and incompatibilities.
Update the existing file trigger tests to cover this case.
Fixes: #3029
Each library target's exported `INTERFACE_INCLUDE_DIRECTORIES` list,
as written into the `rpm-targets.cmake` export file, is controlled by
the `PUBLIC` arguments supplied to `target_include_directories()` for
the library target.
* Directories scoped with the `$<BUILD_INTERFACE>` generator expression
will be included in the export file written to the build dir by
`export(TARGETS...)`
* Directories scoped with `$<INSTALL_INTERFACE>` will be included in
the `rpm-targets.cmake` file installed into the
`${CMAKE_INSTALL_LIBDIR}/cmake/rpm/` configuration directory.
Providing `PUBLIC` include directory paths for both the build and
install contexts is important, because without them the exported
CMake configuration is useless to library consumers.
(If the build is installed into `/usr/` or `/usr/local` it won't
matter, because the include directories required are the default
`/usr/include` or `/usr/local/include/` paths. But an install
targeted elsewhere with a `CMAKE_INSTALL_PREFIX` path needs an
`INTERFACE_INCLUDE_DIRECTORIES` property of
`${CMAKE_INSTALL_INCLUDEDIR}` to correctly locate its installed
includes.)
As of v1.7.0, `rpm-sequoia` implements `pgpPubkeyMerge`. Bump the
minimum supported version of `rpm-sequoia` to v1.7.0, and replace the
`pgpPubkeyMerge` stub with `rpm-sequoia`'s implementation of
`pgpPubkeyMerge`.
$ rpm --define 'aaa %[%aaa]' --eval '%aaa'
let to a core dump due to a stack overflow. This was cause by the
generation of the error message failing due to being too deep in the
recursion of the macro expansion - creating more error messages.
Resetting the depth counter allows rendering the error message. As we are
failing and breaking off the parse run this is fine to do.
Thanks to Miro Hrončok for reporting
Resolves: #3197
Rpm allows URLs as cli parameters. The files are then automatically
downloaded with %_urlhelper which defaults to curl(1). So far failures
have been ignored right away and error messages are generated later when
the file was not found on disk.
Issue a meaningful error message when the help program is failing or missing
completely. This allows not to ship curl with rpm while still giving the
user a chance to find out what is going on. This is not quite ideal as
the operation continues and creates a second error message later on, but
as good as it gets without redesigning the whole code.
Related: rhbz#2216754
Resolves: #2683
Somehow this never got updated to rpmhash, so it was carrying a whole
hash implementation on its own. Lotsa fubar goes away.
Natively allocate rpmhook args too, and use a vector
Removes the arbitrary limit of ids we support. Not that rpm needs more,
but arbitrary is arbitrary. Technically it's more efficient because
we don't need to brute-force search and there are never inactive digests
to skip when updating, but given the small number of elements it's
unlikely to make any real-world difference.
Also remove the unused nbytes member, I don't recall why I added it
but it hasn't been grown any uses in 10+ years so might as well drop.
The new rpmPubkeyMerge function will merge the certificate
material of two pubkeys describing the same key.
This is currently only implemented in the "legcay" backend.
Use this method in rpmtsImportPubkey() to check if we already
have that key. This is the place where we will implement key
merging in the next commits.
If the resulting flags cannot be returned, the caller has no way to
strip the quote characters. So we must assume that we are not to
return quotes in this case.
Fixes issue #3145
Use an STL stack to store the macro entries sharing the name to separate
the data from its containing structure, this lets the macro entries be
proper C++ objects that manage their own business only and thus can be
also directly stored containers, doing away with manual allocation.
And now that these entries no longer need any special care, we can
delete all the copy-control fubar from the main macro context: it's all
standard library storage now and don't need our handholding.
Use an STL map for the macro entry table, this matches exactly the behavior
we manually did with the C array.
The variable length array at end of macro entry structs is not really
C++, use native strings for the storage. It's slower, but not tragically
so. For now, keep name, opts and body as const char pointers though to
the c_str() items to avoid having to change everything at once.
Popping macros is a bit clunky and repetitive, we'll clean it up later.
findEntry() returns a pointer to the macro entry itself instead of
pointer to pointer, which simplifies things a bit further.
This is a wee bit slower than the "raw C" counterpart, but by no means
tragically so and moving to native structures opens up other opportunities
in turn, both optimization and feature wise. Further work will be easier
now that the highly optimized but also tangled up data structure is
(mostly) untangled.
The macro contexts being static structs, they get their destructor
automatically called at program end. Which counter-intuitively *causes*
a leak if macros are stored in an STL container and rpmFreeMacros()
isn't called, because then the container clears itself and the macros
are left dangling, whereas without the destructor they are still
reachable. freeMacros() obviously wants to be a member function but
trying to keep things in the struct land for now.
Doesn't really change anything as of now, but this is needed for moving
the macro storage to C++ container.
C++ strings can hold \0's so we can use it for convenient storage of
keyids, passing them to C requires special attention anyhow. And then
we can easily replace all array bookkeeping and lookup fubar with
STL map. We could just as easily use unordered_map, but map matches
what it did before so...
freeArgs() only popped any local macros once, so if a local macro was
pushed multiple times, whether through %define or multiple identical
options getting passed, we leaked any remaining macros to the outside
scope.
Simply pop the local macros in a loop to fix. Have the internal
popMacro() return the previous pointer (if any) to simplify the job.
We even had an expected-fail test for this, now passing, but add a
more straightforward reproducer too.
This bug was circa 26 years old. Some might call it vintage at this point.
Fixes: #3056
A stupid newbie C++ error, array allocation would've been "new uint8_t[nb]"
and requiring delete[] as well. Use a vector instead, then we don't
need to manually free or track the size.
We really need to test the optional io types too, eww.
Rename some internal structs to common style, the dust is thick in this
part of the cellar. In particular "lzfile" as a struct name clashes with
our local variables, don't do that.
Some background + rationale that will apply to a lot more commits going
forward and not going to keep repeating it all, so using this as a cover
letter of sorts:
Converting rpm to something resembling C++ is going to be a multi-year
operation, and what is being done here is just the first step of many.
Moving to native C++ allocation seems like an important first step as it
allows using non-trivial C++ data types (such as strings) in said constructs
(with malloc/free, destructors do not run). Also, it brings down the
number of raw C allocations with their ugly casts. It's worth nothing
that we'll never be free of raw mallocs entirely as some of the allocations
we return are expected to be free()'d from C, such as the output
parameter of rpmDigestFinal(). So we just want to get to the state where
ALL C-style allocations are for data going across the API border as
quickly as possible, the mixed state of things is ugly and fragile.
In many places rpm is relying on calloc() or memset() to zero-initialize
structs, but this cannot be used on C++ structs with "non-trivial" data
types such as strings, STL containers and the like. The {}
initialization is the nearest C++ counterpart for that. It'd be safer
to place the initialization(s) in the struct members directly but we're
shooting for minimal changes at this point, that'll come later.
Finally, we are using "naked new" because many of our pointers are going
across the API border to C where smart pointers simply cannot be used,
not without extra tricks anyhow. We don't want to worry about that just
now. We'll be using "naked new" for internal pointers too initially, again
just to keep changes minimal.
rpmlogCallbackData is already a pointer type, we don't want a pointer
to a pointer for this. Kinda surprising it actually worked, but then
it's just a void pointer so...