| // Copyright 2021 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "bootid-logger/timestamp_util.h" |
| |
| #include <memory> |
| #include <string> |
| |
| #include <base/files/file_enumerator.h> |
| #include <base/files/file_util.h> |
| |
| #include "bootid-logger/constants.h" |
| #include "croslog/log_entry_reader.h" |
| #include "croslog/log_parser_syslog.h" |
| |
| // The list is coped from /platform2/init/chromeos-cleanup-logs |
| // TODO(crbug.com/1168393): share the list with the rotation script. |
| const char* kLogFiles[] = {"messages", |
| "secure", |
| "net.log", |
| "faillog", |
| "session_manager", |
| "atrus.log", |
| "tlsdate.log", |
| "authpolicy.log", |
| "tpm-firmware-updater.log", |
| "arc.log", |
| "recover_duts/recover_duts.log", |
| "hammerd.log", |
| "upstart.log", |
| "typecd.log", |
| "bluetooth.log", |
| NULL}; |
| |
| base::FilePath kLogDir("/var/log"); |
| |
| base::Time GetFirstTimestamp(const base::FilePath& file) { |
| croslog::LogEntryReader reader( |
| file, std::make_unique<croslog::LogParserSyslog>(), false); |
| croslog::MaybeLogEntry e = reader.GetNextEntry(); |
| if (e.has_value()) |
| return e->time(); |
| |
| return base::Time(); |
| } |
| |
| base::Time GetOldestTimestampFromLogFiles(const base::FilePath& dir_path, |
| const std::string& base_log_name) { |
| base::Time oldest_last_modified; |
| |
| // Retrieve the path and the last modified date of the latest log file |
| // (without a suffix). |
| { |
| base::FilePath log_file_path = dir_path.Append(base_log_name); |
| if (base::PathExists(log_file_path)) |
| oldest_last_modified = GetFirstTimestamp(log_file_path); |
| } |
| |
| // Pattern to match the older log files with suffix. |
| std::string pattern = base_log_name + ".*"; |
| |
| // Traverse the older log files. |
| base::FileEnumerator e(dir_path, false, base::FileEnumerator::FILES, pattern); |
| for (base::FilePath name = e.Next(); !name.empty(); name = e.Next()) { |
| base::Time last_modified = GetFirstTimestamp(name); |
| |
| // If the first timestamp can't be retrieved, Use the timestamp one day |
| // prior to the last modifiled time of the file (assumeing the file is |
| // rotated daily). |
| if (last_modified.is_null()) |
| last_modified = |
| e.GetInfo().GetLastModifiedTime() - base::TimeDelta::FromDays(1); |
| |
| if (last_modified.is_null()) |
| continue; |
| |
| if (oldest_last_modified.is_null() || oldest_last_modified > last_modified) |
| oldest_last_modified = last_modified; |
| } |
| |
| return oldest_last_modified; |
| } |
| |
| base::Time GetOldestModifiedTime(base::FilePath log_directory, |
| const char* log_files[]) { |
| base::Time oldest_last_modified; |
| |
| for (int i = 0; log_files[i] != NULL; i++) { |
| base::Time last_modified = |
| GetOldestTimestampFromLogFiles(log_directory, log_files[i]); |
| |
| if (last_modified.is_null()) |
| continue; |
| |
| if (oldest_last_modified.is_null() || oldest_last_modified > last_modified) |
| oldest_last_modified = last_modified; |
| } |
| |
| return oldest_last_modified; |
| } |
| |
| base::Time GetOldestModifiedTime() { |
| return GetOldestModifiedTime(kLogDir, kLogFiles); |
| } |
| |
| // Extracts the boot ID from the givin boot ID entry. |
| base::Time ExtractTimestampString(const std::string& boot_id_entry) { |
| base::Time time; |
| |
| if (boot_id_entry[26] == 'Z') { |
| // Case of UTC time format like "2020-05-25T00:00:00.000000Z". |
| std::string log_time = boot_id_entry.substr(0, kTimestampLength); |
| |
| bool result = base::Time::FromString(log_time.c_str(), &time); |
| if (!result) |
| return base::Time(); |
| |
| return time; |
| } else if (boot_id_entry[26] == '+' || boot_id_entry[26] == '-') { |
| // Case of format with time-zone like "2020-05-25T00:00:00.000000+00:00". |
| std::string log_time = boot_id_entry.substr(0, kLocalTimeTimestampLength); |
| |
| bool result = base::Time::FromString(log_time.c_str(), &time); |
| if (!result) |
| return base::Time(); |
| |
| return time; |
| } |
| |
| // Returning a null time as an error. |
| return base::Time(); |
| } |