1*e7c364b6SAndroid Build Coastguard Worker /*
2*e7c364b6SAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project
3*e7c364b6SAndroid Build Coastguard Worker *
4*e7c364b6SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*e7c364b6SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*e7c364b6SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*e7c364b6SAndroid Build Coastguard Worker *
8*e7c364b6SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*e7c364b6SAndroid Build Coastguard Worker *
10*e7c364b6SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*e7c364b6SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*e7c364b6SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e7c364b6SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*e7c364b6SAndroid Build Coastguard Worker * limitations under the License.
15*e7c364b6SAndroid Build Coastguard Worker */
16*e7c364b6SAndroid Build Coastguard Worker
17*e7c364b6SAndroid Build Coastguard Worker #include "recovery_utils/logging.h"
18*e7c364b6SAndroid Build Coastguard Worker
19*e7c364b6SAndroid Build Coastguard Worker #include <dirent.h>
20*e7c364b6SAndroid Build Coastguard Worker #include <errno.h>
21*e7c364b6SAndroid Build Coastguard Worker #include <stdio.h>
22*e7c364b6SAndroid Build Coastguard Worker #include <string.h>
23*e7c364b6SAndroid Build Coastguard Worker #include <sys/klog.h>
24*e7c364b6SAndroid Build Coastguard Worker #include <sys/types.h>
25*e7c364b6SAndroid Build Coastguard Worker
26*e7c364b6SAndroid Build Coastguard Worker #include <algorithm>
27*e7c364b6SAndroid Build Coastguard Worker #include <memory>
28*e7c364b6SAndroid Build Coastguard Worker #include <string>
29*e7c364b6SAndroid Build Coastguard Worker
30*e7c364b6SAndroid Build Coastguard Worker #include <android-base/file.h>
31*e7c364b6SAndroid Build Coastguard Worker #include <android-base/logging.h>
32*e7c364b6SAndroid Build Coastguard Worker #include <android-base/parseint.h>
33*e7c364b6SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
34*e7c364b6SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
35*e7c364b6SAndroid Build Coastguard Worker #include <private/android_filesystem_config.h> /* for AID_SYSTEM */
36*e7c364b6SAndroid Build Coastguard Worker #include <private/android_logger.h> /* private pmsg functions */
37*e7c364b6SAndroid Build Coastguard Worker #include <selinux/label.h>
38*e7c364b6SAndroid Build Coastguard Worker
39*e7c364b6SAndroid Build Coastguard Worker #include "otautil/dirutil.h"
40*e7c364b6SAndroid Build Coastguard Worker #include "otautil/paths.h"
41*e7c364b6SAndroid Build Coastguard Worker #include "recovery_utils/roots.h"
42*e7c364b6SAndroid Build Coastguard Worker
43*e7c364b6SAndroid Build Coastguard Worker constexpr const char* LOG_FILE = "/cache/recovery/log";
44*e7c364b6SAndroid Build Coastguard Worker constexpr const char* LAST_INSTALL_FILE = "/cache/recovery/last_install";
45*e7c364b6SAndroid Build Coastguard Worker constexpr const char* LAST_KMSG_FILE = "/cache/recovery/last_kmsg";
46*e7c364b6SAndroid Build Coastguard Worker constexpr const char* LAST_LOG_FILE = "/cache/recovery/last_log";
47*e7c364b6SAndroid Build Coastguard Worker
48*e7c364b6SAndroid Build Coastguard Worker constexpr const char* LAST_KMSG_FILTER = "recovery/last_kmsg";
49*e7c364b6SAndroid Build Coastguard Worker constexpr const char* LAST_LOG_FILTER = "recovery/last_log";
50*e7c364b6SAndroid Build Coastguard Worker
51*e7c364b6SAndroid Build Coastguard Worker constexpr const char* CACHE_LOG_DIR = "/cache/recovery";
52*e7c364b6SAndroid Build Coastguard Worker
53*e7c364b6SAndroid Build Coastguard Worker static struct selabel_handle* logging_sehandle;
54*e7c364b6SAndroid Build Coastguard Worker
SetLoggingSehandle(selabel_handle * handle)55*e7c364b6SAndroid Build Coastguard Worker void SetLoggingSehandle(selabel_handle* handle) {
56*e7c364b6SAndroid Build Coastguard Worker logging_sehandle = handle;
57*e7c364b6SAndroid Build Coastguard Worker }
58*e7c364b6SAndroid Build Coastguard Worker
59*e7c364b6SAndroid Build Coastguard Worker // fopen(3)'s the given file, by mounting volumes and making parent dirs as necessary. Returns the
60*e7c364b6SAndroid Build Coastguard Worker // file pointer, or nullptr on error.
fopen_path(const std::string & path,const char * mode,const selabel_handle * sehandle)61*e7c364b6SAndroid Build Coastguard Worker static FILE* fopen_path(const std::string& path, const char* mode, const selabel_handle* sehandle) {
62*e7c364b6SAndroid Build Coastguard Worker if (ensure_path_mounted(path) != 0) {
63*e7c364b6SAndroid Build Coastguard Worker LOG(ERROR) << "Can't mount " << path;
64*e7c364b6SAndroid Build Coastguard Worker return nullptr;
65*e7c364b6SAndroid Build Coastguard Worker }
66*e7c364b6SAndroid Build Coastguard Worker
67*e7c364b6SAndroid Build Coastguard Worker // When writing, try to create the containing directory, if necessary. Use generous permissions,
68*e7c364b6SAndroid Build Coastguard Worker // the system (init.rc) will reset them.
69*e7c364b6SAndroid Build Coastguard Worker if (strchr("wa", mode[0])) {
70*e7c364b6SAndroid Build Coastguard Worker mkdir_recursively(path, 0777, true, sehandle);
71*e7c364b6SAndroid Build Coastguard Worker }
72*e7c364b6SAndroid Build Coastguard Worker return fopen(path.c_str(), mode);
73*e7c364b6SAndroid Build Coastguard Worker }
74*e7c364b6SAndroid Build Coastguard Worker
check_and_fclose(FILE * fp,const std::string & name)75*e7c364b6SAndroid Build Coastguard Worker void check_and_fclose(FILE* fp, const std::string& name) {
76*e7c364b6SAndroid Build Coastguard Worker fflush(fp);
77*e7c364b6SAndroid Build Coastguard Worker if (fsync(fileno(fp)) == -1) {
78*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to fsync " << name;
79*e7c364b6SAndroid Build Coastguard Worker }
80*e7c364b6SAndroid Build Coastguard Worker if (ferror(fp)) {
81*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Error in " << name;
82*e7c364b6SAndroid Build Coastguard Worker }
83*e7c364b6SAndroid Build Coastguard Worker fclose(fp);
84*e7c364b6SAndroid Build Coastguard Worker }
85*e7c364b6SAndroid Build Coastguard Worker
86*e7c364b6SAndroid Build Coastguard Worker // close a file, log an error if the error indicator is set
logbasename(log_id_t,char,const char * filename,const char *,size_t len,void * arg)87*e7c364b6SAndroid Build Coastguard Worker ssize_t logbasename(log_id_t /* id */, char /* prio */, const char* filename, const char* /* buf */,
88*e7c364b6SAndroid Build Coastguard Worker size_t len, void* arg) {
89*e7c364b6SAndroid Build Coastguard Worker bool* do_rotate = static_cast<bool*>(arg);
90*e7c364b6SAndroid Build Coastguard Worker if (std::string(LAST_KMSG_FILTER).find(filename) != std::string::npos ||
91*e7c364b6SAndroid Build Coastguard Worker std::string(LAST_LOG_FILTER).find(filename) != std::string::npos) {
92*e7c364b6SAndroid Build Coastguard Worker *do_rotate = true;
93*e7c364b6SAndroid Build Coastguard Worker }
94*e7c364b6SAndroid Build Coastguard Worker return len;
95*e7c364b6SAndroid Build Coastguard Worker }
96*e7c364b6SAndroid Build Coastguard Worker
logrotate(log_id_t id,char prio,const char * filename,const char * buf,size_t len,void * arg)97*e7c364b6SAndroid Build Coastguard Worker ssize_t logrotate(log_id_t id, char prio, const char* filename, const char* buf, size_t len,
98*e7c364b6SAndroid Build Coastguard Worker void* arg) {
99*e7c364b6SAndroid Build Coastguard Worker bool* do_rotate = static_cast<bool*>(arg);
100*e7c364b6SAndroid Build Coastguard Worker if (!*do_rotate) {
101*e7c364b6SAndroid Build Coastguard Worker return __android_log_pmsg_file_write(id, prio, filename, buf, len);
102*e7c364b6SAndroid Build Coastguard Worker }
103*e7c364b6SAndroid Build Coastguard Worker
104*e7c364b6SAndroid Build Coastguard Worker std::string name(filename);
105*e7c364b6SAndroid Build Coastguard Worker size_t dot = name.find_last_of('.');
106*e7c364b6SAndroid Build Coastguard Worker std::string sub = name.substr(0, dot);
107*e7c364b6SAndroid Build Coastguard Worker
108*e7c364b6SAndroid Build Coastguard Worker if (std::string(LAST_KMSG_FILTER).find(sub) == std::string::npos &&
109*e7c364b6SAndroid Build Coastguard Worker std::string(LAST_LOG_FILTER).find(sub) == std::string::npos) {
110*e7c364b6SAndroid Build Coastguard Worker return __android_log_pmsg_file_write(id, prio, filename, buf, len);
111*e7c364b6SAndroid Build Coastguard Worker }
112*e7c364b6SAndroid Build Coastguard Worker
113*e7c364b6SAndroid Build Coastguard Worker // filename rotation
114*e7c364b6SAndroid Build Coastguard Worker if (dot == std::string::npos) {
115*e7c364b6SAndroid Build Coastguard Worker name += ".1";
116*e7c364b6SAndroid Build Coastguard Worker } else {
117*e7c364b6SAndroid Build Coastguard Worker std::string number = name.substr(dot + 1);
118*e7c364b6SAndroid Build Coastguard Worker if (!isdigit(number[0])) {
119*e7c364b6SAndroid Build Coastguard Worker name += ".1";
120*e7c364b6SAndroid Build Coastguard Worker } else {
121*e7c364b6SAndroid Build Coastguard Worker size_t i;
122*e7c364b6SAndroid Build Coastguard Worker if (!android::base::ParseUint(number, &i)) {
123*e7c364b6SAndroid Build Coastguard Worker LOG(ERROR) << "failed to parse uint in " << number;
124*e7c364b6SAndroid Build Coastguard Worker return -1;
125*e7c364b6SAndroid Build Coastguard Worker }
126*e7c364b6SAndroid Build Coastguard Worker name = sub + "." + std::to_string(i + 1);
127*e7c364b6SAndroid Build Coastguard Worker }
128*e7c364b6SAndroid Build Coastguard Worker }
129*e7c364b6SAndroid Build Coastguard Worker
130*e7c364b6SAndroid Build Coastguard Worker return __android_log_pmsg_file_write(id, prio, name.c_str(), buf, len);
131*e7c364b6SAndroid Build Coastguard Worker }
132*e7c364b6SAndroid Build Coastguard Worker
133*e7c364b6SAndroid Build Coastguard Worker // Rename last_log -> last_log.1 -> last_log.2 -> ... -> last_log.$max.
134*e7c364b6SAndroid Build Coastguard Worker // Similarly rename last_kmsg -> last_kmsg.1 -> ... -> last_kmsg.$max.
135*e7c364b6SAndroid Build Coastguard Worker // Overwrite any existing last_log.$max and last_kmsg.$max.
rotate_logs(const char * last_log_file,const char * last_kmsg_file)136*e7c364b6SAndroid Build Coastguard Worker void rotate_logs(const char* last_log_file, const char* last_kmsg_file) {
137*e7c364b6SAndroid Build Coastguard Worker // Logs should only be rotated once.
138*e7c364b6SAndroid Build Coastguard Worker static bool rotated = false;
139*e7c364b6SAndroid Build Coastguard Worker if (rotated) {
140*e7c364b6SAndroid Build Coastguard Worker return;
141*e7c364b6SAndroid Build Coastguard Worker }
142*e7c364b6SAndroid Build Coastguard Worker rotated = true;
143*e7c364b6SAndroid Build Coastguard Worker
144*e7c364b6SAndroid Build Coastguard Worker for (int i = KEEP_LOG_COUNT - 1; i >= 0; --i) {
145*e7c364b6SAndroid Build Coastguard Worker std::string old_log = android::base::StringPrintf("%s", last_log_file);
146*e7c364b6SAndroid Build Coastguard Worker if (i > 0) {
147*e7c364b6SAndroid Build Coastguard Worker old_log += "." + std::to_string(i);
148*e7c364b6SAndroid Build Coastguard Worker }
149*e7c364b6SAndroid Build Coastguard Worker std::string new_log = android::base::StringPrintf("%s.%d", last_log_file, i + 1);
150*e7c364b6SAndroid Build Coastguard Worker // Ignore errors if old_log doesn't exist.
151*e7c364b6SAndroid Build Coastguard Worker rename(old_log.c_str(), new_log.c_str());
152*e7c364b6SAndroid Build Coastguard Worker
153*e7c364b6SAndroid Build Coastguard Worker std::string old_kmsg = android::base::StringPrintf("%s", last_kmsg_file);
154*e7c364b6SAndroid Build Coastguard Worker if (i > 0) {
155*e7c364b6SAndroid Build Coastguard Worker old_kmsg += "." + std::to_string(i);
156*e7c364b6SAndroid Build Coastguard Worker }
157*e7c364b6SAndroid Build Coastguard Worker std::string new_kmsg = android::base::StringPrintf("%s.%d", last_kmsg_file, i + 1);
158*e7c364b6SAndroid Build Coastguard Worker rename(old_kmsg.c_str(), new_kmsg.c_str());
159*e7c364b6SAndroid Build Coastguard Worker }
160*e7c364b6SAndroid Build Coastguard Worker }
161*e7c364b6SAndroid Build Coastguard Worker
162*e7c364b6SAndroid Build Coastguard Worker // Writes content to the current pmsg session.
__pmsg_write(const std::string & filename,const std::string & buf)163*e7c364b6SAndroid Build Coastguard Worker static ssize_t __pmsg_write(const std::string& filename, const std::string& buf) {
164*e7c364b6SAndroid Build Coastguard Worker return __android_log_pmsg_file_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO, filename.c_str(),
165*e7c364b6SAndroid Build Coastguard Worker buf.data(), buf.size());
166*e7c364b6SAndroid Build Coastguard Worker }
167*e7c364b6SAndroid Build Coastguard Worker
copy_log_file_to_pmsg(const std::string & source,const std::string & destination)168*e7c364b6SAndroid Build Coastguard Worker void copy_log_file_to_pmsg(const std::string& source, const std::string& destination) {
169*e7c364b6SAndroid Build Coastguard Worker std::string content;
170*e7c364b6SAndroid Build Coastguard Worker android::base::ReadFileToString(source, &content);
171*e7c364b6SAndroid Build Coastguard Worker __pmsg_write(destination, content);
172*e7c364b6SAndroid Build Coastguard Worker }
173*e7c364b6SAndroid Build Coastguard Worker
174*e7c364b6SAndroid Build Coastguard Worker // How much of the temp log we have copied to the copy in cache.
175*e7c364b6SAndroid Build Coastguard Worker static off_t tmplog_offset = 0;
176*e7c364b6SAndroid Build Coastguard Worker
reset_tmplog_offset()177*e7c364b6SAndroid Build Coastguard Worker void reset_tmplog_offset() {
178*e7c364b6SAndroid Build Coastguard Worker tmplog_offset = 0;
179*e7c364b6SAndroid Build Coastguard Worker }
180*e7c364b6SAndroid Build Coastguard Worker
copy_log_file(const std::string & source,const std::string & destination,bool append)181*e7c364b6SAndroid Build Coastguard Worker static void copy_log_file(const std::string& source, const std::string& destination, bool append) {
182*e7c364b6SAndroid Build Coastguard Worker FILE* dest_fp = fopen_path(destination, append ? "ae" : "we", logging_sehandle);
183*e7c364b6SAndroid Build Coastguard Worker if (dest_fp == nullptr) {
184*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Can't open " << destination;
185*e7c364b6SAndroid Build Coastguard Worker } else {
186*e7c364b6SAndroid Build Coastguard Worker FILE* source_fp = fopen(source.c_str(), "re");
187*e7c364b6SAndroid Build Coastguard Worker if (source_fp != nullptr) {
188*e7c364b6SAndroid Build Coastguard Worker if (append) {
189*e7c364b6SAndroid Build Coastguard Worker fseeko(source_fp, tmplog_offset, SEEK_SET); // Since last write
190*e7c364b6SAndroid Build Coastguard Worker }
191*e7c364b6SAndroid Build Coastguard Worker char buf[4096];
192*e7c364b6SAndroid Build Coastguard Worker size_t bytes;
193*e7c364b6SAndroid Build Coastguard Worker while ((bytes = fread(buf, 1, sizeof(buf), source_fp)) != 0) {
194*e7c364b6SAndroid Build Coastguard Worker fwrite(buf, 1, bytes, dest_fp);
195*e7c364b6SAndroid Build Coastguard Worker }
196*e7c364b6SAndroid Build Coastguard Worker if (append) {
197*e7c364b6SAndroid Build Coastguard Worker tmplog_offset = ftello(source_fp);
198*e7c364b6SAndroid Build Coastguard Worker }
199*e7c364b6SAndroid Build Coastguard Worker check_and_fclose(source_fp, source);
200*e7c364b6SAndroid Build Coastguard Worker }
201*e7c364b6SAndroid Build Coastguard Worker check_and_fclose(dest_fp, destination);
202*e7c364b6SAndroid Build Coastguard Worker }
203*e7c364b6SAndroid Build Coastguard Worker }
204*e7c364b6SAndroid Build Coastguard Worker
copy_logs(bool save_current_log)205*e7c364b6SAndroid Build Coastguard Worker void copy_logs(bool save_current_log) {
206*e7c364b6SAndroid Build Coastguard Worker // We only rotate and record the log of the current session if explicitly requested. This usually
207*e7c364b6SAndroid Build Coastguard Worker // happens after wipes, installation from BCB or menu selections. This is to avoid unnecessary
208*e7c364b6SAndroid Build Coastguard Worker // rotation (and possible deletion) of log files, if it does not do anything loggable.
209*e7c364b6SAndroid Build Coastguard Worker if (!save_current_log) {
210*e7c364b6SAndroid Build Coastguard Worker return;
211*e7c364b6SAndroid Build Coastguard Worker }
212*e7c364b6SAndroid Build Coastguard Worker
213*e7c364b6SAndroid Build Coastguard Worker // Always write to pmsg, this allows the OTA logs to be caught in `logcat -L`.
214*e7c364b6SAndroid Build Coastguard Worker copy_log_file_to_pmsg(Paths::Get().temporary_log_file(), LAST_LOG_FILE);
215*e7c364b6SAndroid Build Coastguard Worker copy_log_file_to_pmsg(Paths::Get().temporary_install_file(), LAST_INSTALL_FILE);
216*e7c364b6SAndroid Build Coastguard Worker
217*e7c364b6SAndroid Build Coastguard Worker // We can do nothing for now if there's no /cache partition.
218*e7c364b6SAndroid Build Coastguard Worker if (!HasCache()) {
219*e7c364b6SAndroid Build Coastguard Worker return;
220*e7c364b6SAndroid Build Coastguard Worker }
221*e7c364b6SAndroid Build Coastguard Worker
222*e7c364b6SAndroid Build Coastguard Worker ensure_path_mounted(LAST_LOG_FILE);
223*e7c364b6SAndroid Build Coastguard Worker ensure_path_mounted(LAST_KMSG_FILE);
224*e7c364b6SAndroid Build Coastguard Worker rotate_logs(LAST_LOG_FILE, LAST_KMSG_FILE);
225*e7c364b6SAndroid Build Coastguard Worker
226*e7c364b6SAndroid Build Coastguard Worker // Copy logs to cache so the system can find out what happened.
227*e7c364b6SAndroid Build Coastguard Worker copy_log_file(Paths::Get().temporary_log_file(), LOG_FILE, true);
228*e7c364b6SAndroid Build Coastguard Worker copy_log_file(Paths::Get().temporary_log_file(), LAST_LOG_FILE, false);
229*e7c364b6SAndroid Build Coastguard Worker copy_log_file(Paths::Get().temporary_install_file(), LAST_INSTALL_FILE, false);
230*e7c364b6SAndroid Build Coastguard Worker save_kernel_log(LAST_KMSG_FILE);
231*e7c364b6SAndroid Build Coastguard Worker chmod(LOG_FILE, 0600);
232*e7c364b6SAndroid Build Coastguard Worker chown(LOG_FILE, AID_SYSTEM, AID_SYSTEM);
233*e7c364b6SAndroid Build Coastguard Worker chmod(LAST_KMSG_FILE, 0600);
234*e7c364b6SAndroid Build Coastguard Worker chown(LAST_KMSG_FILE, AID_SYSTEM, AID_SYSTEM);
235*e7c364b6SAndroid Build Coastguard Worker chmod(LAST_LOG_FILE, 0640);
236*e7c364b6SAndroid Build Coastguard Worker chmod(LAST_INSTALL_FILE, 0644);
237*e7c364b6SAndroid Build Coastguard Worker chown(LAST_INSTALL_FILE, AID_SYSTEM, AID_SYSTEM);
238*e7c364b6SAndroid Build Coastguard Worker sync();
239*e7c364b6SAndroid Build Coastguard Worker }
240*e7c364b6SAndroid Build Coastguard Worker
241*e7c364b6SAndroid Build Coastguard Worker // Read from kernel log into buffer and write out to file.
save_kernel_log(const char * destination)242*e7c364b6SAndroid Build Coastguard Worker void save_kernel_log(const char* destination) {
243*e7c364b6SAndroid Build Coastguard Worker int klog_buf_len = klogctl(KLOG_SIZE_BUFFER, 0, 0);
244*e7c364b6SAndroid Build Coastguard Worker if (klog_buf_len <= 0) {
245*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Error getting klog size";
246*e7c364b6SAndroid Build Coastguard Worker return;
247*e7c364b6SAndroid Build Coastguard Worker }
248*e7c364b6SAndroid Build Coastguard Worker
249*e7c364b6SAndroid Build Coastguard Worker std::string buffer(klog_buf_len, 0);
250*e7c364b6SAndroid Build Coastguard Worker int n = klogctl(KLOG_READ_ALL, &buffer[0], klog_buf_len);
251*e7c364b6SAndroid Build Coastguard Worker if (n == -1) {
252*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Error in reading klog";
253*e7c364b6SAndroid Build Coastguard Worker return;
254*e7c364b6SAndroid Build Coastguard Worker }
255*e7c364b6SAndroid Build Coastguard Worker buffer.resize(n);
256*e7c364b6SAndroid Build Coastguard Worker android::base::WriteStringToFile(buffer, destination);
257*e7c364b6SAndroid Build Coastguard Worker }
258*e7c364b6SAndroid Build Coastguard Worker
ReadLogFilesToMemory()259*e7c364b6SAndroid Build Coastguard Worker std::vector<saved_log_file> ReadLogFilesToMemory() {
260*e7c364b6SAndroid Build Coastguard Worker ensure_path_mounted("/cache");
261*e7c364b6SAndroid Build Coastguard Worker
262*e7c364b6SAndroid Build Coastguard Worker struct dirent* de;
263*e7c364b6SAndroid Build Coastguard Worker std::unique_ptr<DIR, decltype(&closedir)> d(opendir(CACHE_LOG_DIR), closedir);
264*e7c364b6SAndroid Build Coastguard Worker if (!d) {
265*e7c364b6SAndroid Build Coastguard Worker if (errno != ENOENT) {
266*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to opendir " << CACHE_LOG_DIR;
267*e7c364b6SAndroid Build Coastguard Worker }
268*e7c364b6SAndroid Build Coastguard Worker return {};
269*e7c364b6SAndroid Build Coastguard Worker }
270*e7c364b6SAndroid Build Coastguard Worker
271*e7c364b6SAndroid Build Coastguard Worker std::vector<saved_log_file> log_files;
272*e7c364b6SAndroid Build Coastguard Worker while ((de = readdir(d.get())) != nullptr) {
273*e7c364b6SAndroid Build Coastguard Worker if (strncmp(de->d_name, "last_", 5) == 0 || strcmp(de->d_name, "log") == 0) {
274*e7c364b6SAndroid Build Coastguard Worker std::string path = android::base::StringPrintf("%s/%s", CACHE_LOG_DIR, de->d_name);
275*e7c364b6SAndroid Build Coastguard Worker
276*e7c364b6SAndroid Build Coastguard Worker struct stat sb;
277*e7c364b6SAndroid Build Coastguard Worker if (stat(path.c_str(), &sb) != 0) {
278*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to stat " << path;
279*e7c364b6SAndroid Build Coastguard Worker continue;
280*e7c364b6SAndroid Build Coastguard Worker }
281*e7c364b6SAndroid Build Coastguard Worker // Truncate files to 512kb
282*e7c364b6SAndroid Build Coastguard Worker size_t read_size = std::min<size_t>(sb.st_size, 1 << 19);
283*e7c364b6SAndroid Build Coastguard Worker std::string data(read_size, '\0');
284*e7c364b6SAndroid Build Coastguard Worker
285*e7c364b6SAndroid Build Coastguard Worker android::base::unique_fd log_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY)));
286*e7c364b6SAndroid Build Coastguard Worker if (log_fd == -1 || !android::base::ReadFully(log_fd, data.data(), read_size)) {
287*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to read log file " << path;
288*e7c364b6SAndroid Build Coastguard Worker continue;
289*e7c364b6SAndroid Build Coastguard Worker }
290*e7c364b6SAndroid Build Coastguard Worker
291*e7c364b6SAndroid Build Coastguard Worker log_files.emplace_back(saved_log_file{ path, sb, data });
292*e7c364b6SAndroid Build Coastguard Worker }
293*e7c364b6SAndroid Build Coastguard Worker }
294*e7c364b6SAndroid Build Coastguard Worker
295*e7c364b6SAndroid Build Coastguard Worker return log_files;
296*e7c364b6SAndroid Build Coastguard Worker }
297*e7c364b6SAndroid Build Coastguard Worker
RestoreLogFilesAfterFormat(const std::vector<saved_log_file> & log_files)298*e7c364b6SAndroid Build Coastguard Worker bool RestoreLogFilesAfterFormat(const std::vector<saved_log_file>& log_files) {
299*e7c364b6SAndroid Build Coastguard Worker // Re-create the log dir and write back the log entries.
300*e7c364b6SAndroid Build Coastguard Worker if (ensure_path_mounted(CACHE_LOG_DIR) != 0) {
301*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to mount " << CACHE_LOG_DIR;
302*e7c364b6SAndroid Build Coastguard Worker return false;
303*e7c364b6SAndroid Build Coastguard Worker }
304*e7c364b6SAndroid Build Coastguard Worker
305*e7c364b6SAndroid Build Coastguard Worker if (mkdir_recursively(CACHE_LOG_DIR, 0777, false, logging_sehandle) != 0) {
306*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to create " << CACHE_LOG_DIR;
307*e7c364b6SAndroid Build Coastguard Worker return false;
308*e7c364b6SAndroid Build Coastguard Worker }
309*e7c364b6SAndroid Build Coastguard Worker
310*e7c364b6SAndroid Build Coastguard Worker for (const auto& log : log_files) {
311*e7c364b6SAndroid Build Coastguard Worker if (!android::base::WriteStringToFile(log.data, log.name, log.sb.st_mode, log.sb.st_uid,
312*e7c364b6SAndroid Build Coastguard Worker log.sb.st_gid)) {
313*e7c364b6SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to write to " << log.name;
314*e7c364b6SAndroid Build Coastguard Worker }
315*e7c364b6SAndroid Build Coastguard Worker }
316*e7c364b6SAndroid Build Coastguard Worker
317*e7c364b6SAndroid Build Coastguard Worker // Any part of the log we'd copied to cache is now gone.
318*e7c364b6SAndroid Build Coastguard Worker // Reset the pointer so we copy from the beginning of the temp
319*e7c364b6SAndroid Build Coastguard Worker // log.
320*e7c364b6SAndroid Build Coastguard Worker reset_tmplog_offset();
321*e7c364b6SAndroid Build Coastguard Worker copy_logs(true /* save_current_log */);
322*e7c364b6SAndroid Build Coastguard Worker
323*e7c364b6SAndroid Build Coastguard Worker return true;
324*e7c364b6SAndroid Build Coastguard Worker }
325