diff --git a/libdnf5/repo/repo_downloader.cpp b/libdnf5/repo/repo_downloader.cpp index a04d2ff1b..b142aabbe 100644 --- a/libdnf5/repo/repo_downloader.cpp +++ b/libdnf5/repo/repo_downloader.cpp @@ -31,6 +31,7 @@ along with libdnf. If not, see . #include #include #include +#include #include #include @@ -714,7 +715,7 @@ void RepoDownloader::add_countme_flag(LibrepoHandle & handle) { file_path /= COUNTME_COOKIE; int ver = COUNTME_VERSION; // file format version (for future use) - time_t epoch = 0; // position of first-ever counted window + time_t epoch = 0; // position of first observed window time_t win = COUNTME_OFFSET; // position of last counted window int budget = -1; // budget for this window (-1 = generate) // TODO(lukash) ideally replace with utils::fs::File (via adding scanf() support?), @@ -746,8 +747,15 @@ void RepoDownloader::add_countme_flag(LibrepoHandle & handle) { // Compute the position of this window win = now - (delta % COUNTME_WINDOW); + + // Compute the epoch from this system's epoch or, if unknown, declare + // this window as the epoch (unless stored in the cookie previously). + time_t sysepoch = get_system_epoch(); + if (sysepoch) + epoch = sysepoch - ((sysepoch - COUNTME_OFFSET) % COUNTME_WINDOW); if (!epoch) epoch = win; + // Window step (0 at epoch) int64_t step = (win - epoch) / COUNTME_WINDOW; @@ -784,6 +792,31 @@ std::set RepoDownloader::get_optional_metadata() const { } +/* Returns this system's installation time ("epoch") as a UNIX timestamp. + * + * Uses the machine-id(5) file's mtime as a good-enough source of truth. This + * file is typically tied to the system's installation or first boot where it's + * populated by an installer tool or init system, respectively, and is never + * changed afterwards. + * + * Some systems, such as containers that don't run an init system, may have the + * file missing, empty or uninitialized, in which case this function returns 0. + */ +time_t RepoDownloader::get_system_epoch() const { + std::string filename = "/etc/machine-id"; + std::string id; + struct stat st; + + if (stat(filename.c_str(), &st) != 0 || !st.st_size) + return 0; + std::ifstream(filename) >> id; + if (id == "uninitialized") + return 0; + + return st.st_mtime; +} + + //void Downloader::download_url(ConfigMain * cfg, const char * url, int fd) { // std::unique_ptr lr_handle(new_remote_handle(*cfg)); // GError * err_p{nullptr}; diff --git a/libdnf5/repo/repo_downloader.hpp b/libdnf5/repo/repo_downloader.hpp index f6adcf7ef..1c14b272b 100644 --- a/libdnf5/repo/repo_downloader.hpp +++ b/libdnf5/repo/repo_downloader.hpp @@ -96,6 +96,7 @@ class RepoDownloader { std::string get_persistdir() const; void add_countme_flag(LibrepoHandle & handle); + time_t get_system_epoch() const; std::set get_optional_metadata() const;