On Sun, 2025-04-27 at 16:18 +0200, Ben Hutchings wrote: [...] > - If I mask packagekit.service before booting (using a rescue shell), > then none of the files are updated automatically. Running 'apt > update' updates them all as expected. > > So it seems like this problem may be specific to PackageKit. > > Sven and Laurent, do your affected systems have PackageKit installed?
OK, so I think this is confirmed as somehow PackageKit-related. I had a look through the code for "apt update" and the PackageKit APT back-end to see what might be different. I think this has something to do with the different pkgAcquireStatus subclasses they use, but I couldn't identify a specific bug in PackageKit. I experimented with writing a test program that implements its own pkgAcquireStatus, and I I'm attaching the source for that. It needs to be run on a system where a local InRelease file is out of date. If you answer "no" to the Pulse() after the *second* time the InRelease file is reported done, that should reproduce the broken state. (The default answers are set for my VM snapshot which now has very outdated InRelease files, so I know that the Pulse() after a ReleaseInfoChanges() is the place to stop.) Ben. -- Ben Hutchings If at first you don't succeed, you're doing about average.
#include <iostream>
#include <utility>
#include <apt-pkg/acquire.h>
#include <apt-pkg/cachefile.h>
#include <apt-pkg/init.h>
#include <apt-pkg/macros.h>
#include <apt-pkg/pkgsystem.h>
#include <apt-pkg/sourcelist.h>
#include <apt-pkg/update.h>
bool ask_continue(bool answer)
{
char ch = 0;
std::cout << "continue? "
<< (answer ? "[yes]/no" : "yes/[no]")
<< "\n";
while (std::cin.get(ch) && ch != '\n') {
if (ch == 'y' || ch == 'Y')
answer = true;
if (ch == 'n' || ch == 'N')
answer = false;
}
return answer;
}
class StatusHandler : public pkgAcquireStatus
{
public:
StatusHandler()
{
Update = true;
cancel_next_= false;
}
private:
bool cancel_next_;
virtual void Fetched(unsigned long long Size,
unsigned long long ResumePoint) override
{
std::cout << "Fetched: " << Size << "\n";
pkgAcquireStatus::Fetched(Size, ResumePoint);
}
virtual bool MediaChange(std::string /*Media*/,
std::string /*Drive*/) override
{
std::cerr << "MediaChange: returning false\n";
return false;
}
virtual bool ReleaseInfoChanges(
metaIndex const * const LastRelease,
metaIndex const * const CurrentRelease,
std::vector<ReleaseInfoChange> &&Changes) override
{
std::cout << "ReleaseInfoChanges\n";
bool def_answer = pkgAcquireStatus::ReleaseInfoChanges(
LastRelease, CurrentRelease, std::move(Changes));
cancel_next_ = true;
return ask_continue(def_answer);
}
virtual void IMSHit(pkgAcquire::ItemDesc &/*Itm*/) override
{
std::cout << "IMSHit\n";
}
virtual void Fetch(pkgAcquire::ItemDesc &Itm) override
{
std::cout << "Fetch: " << Itm.URI << "\n";
}
virtual void Done(pkgAcquire::ItemDesc &Itm) override
{
std::cout << "Done: " << Itm.URI << "\n";
}
virtual void Fail(pkgAcquire::ItemDesc &Itm) override
{
std::cerr << "Fail: " << Itm.URI << "\n";
}
virtual bool Pulse(pkgAcquire *Owner) override
{
std::cout << "Pulse\n";
bool def_answer = pkgAcquireStatus::Pulse(Owner);
if (cancel_next_) {
def_answer = false;
cancel_next_ = false;
}
return ask_continue(def_answer);
}
virtual void Start() override
{
std::cout << "Start\n";
pkgAcquireStatus::Start();
}
virtual void Stop() override
{
std::cout << "Stop\n";
pkgAcquireStatus::Stop();
}
};
int main(void)
{
pkgCacheFile Cache;
if (!pkgInitConfig(*_config)) {
std::cerr << "pkgInitConfig() failed\n";
return 1;
}
if (!pkgInitSystem(*_config, _system)) {
std::cerr << "pkgInitSystem() failed\n";
return 1;
}
if (!Cache.BuildSourceList()) {
std::cerr << "BuildSourceList() failed\n";
return 1;
}
StatusHandler Stat;
if (!ListUpdate(Stat, *Cache.GetSourceList()))
std::cerr << "ListUpdate() failed\n";
pkgCacheFile::RemoveCaches();
if (!Cache.BuildCaches() == false) {
std::cerr << "BuildCaches() failed\n";
return 1;
}
return 0;
}
signature.asc
Description: This is a digitally signed message part

