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