xref: /aosp_15_r20/bootable/recovery/recovery_utils/logging.cpp (revision e7c364b630b241adcb6c7726a21055250b91fdac)
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