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;
}

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to