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;