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