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 "rotate_logs.h" 18 19 #include <stdio.h> 20 #include <string.h> 21 #include <sys/types.h> 22 23 #include <string> 24 25 #include <android-base/file.h> 26 #include <android-base/logging.h> 27 #include <android-base/parseint.h> 28 #include <android-base/stringprintf.h> 29 #include <private/android_logger.h> /* private pmsg functions */ 30 31 static const std::string LAST_KMSG_FILTER = "recovery/last_kmsg"; 32 static const std::string LAST_LOG_FILTER = "recovery/last_log"; 33 34 ssize_t logbasename( 35 log_id_t /* logId */, 36 char /* prio */, 37 const char *filename, 38 const char * /* buf */, size_t len, 39 void *arg) { 40 bool* doRotate = static_cast<bool*>(arg); 41 if (LAST_KMSG_FILTER.find(filename) != std::string::npos || 42 LAST_LOG_FILTER.find(filename) != std::string::npos) { 43 *doRotate = true; 44 } 45 return len; 46 } 47 48 ssize_t logrotate( 49 log_id_t logId, 50 char prio, 51 const char *filename, 52 const char *buf, size_t len, 53 void *arg) { 54 bool* doRotate = static_cast<bool*>(arg); 55 if (!*doRotate) { 56 return __android_log_pmsg_file_write(logId, prio, filename, buf, len); 57 } 58 59 std::string name(filename); 60 size_t dot = name.find_last_of('.'); 61 std::string sub = name.substr(0, dot); 62 63 if (LAST_KMSG_FILTER.find(sub) == std::string::npos && 64 LAST_LOG_FILTER.find(sub) == std::string::npos) { 65 return __android_log_pmsg_file_write(logId, prio, filename, buf, len); 66 } 67 68 // filename rotation 69 if (dot == std::string::npos) { 70 name += ".1"; 71 } else { 72 std::string number = name.substr(dot + 1); 73 if (!isdigit(number[0])) { 74 name += ".1"; 75 } else { 76 size_t i; 77 if (!android::base::ParseUint(number, &i)) { 78 LOG(ERROR) << "failed to parse uint in " << number; 79 return -1; 80 } 81 name = sub + "." + std::to_string(i + 1); 82 } 83 } 84 85 return __android_log_pmsg_file_write(logId, prio, name.c_str(), buf, len); 86 } 87 88 // Rename last_log -> last_log.1 -> last_log.2 -> ... -> last_log.$max. 89 // Similarly rename last_kmsg -> last_kmsg.1 -> ... -> last_kmsg.$max. 90 // Overwrite any existing last_log.$max and last_kmsg.$max. 91 void rotate_logs(const char* last_log_file, const char* last_kmsg_file) { 92 // Logs should only be rotated once. 93 static bool rotated = false; 94 if (rotated) { 95 return; 96 } 97 rotated = true; 98 99 for (int i = KEEP_LOG_COUNT - 1; i >= 0; --i) { 100 std::string old_log = android::base::StringPrintf("%s", last_log_file); 101 if (i > 0) { 102 old_log += "." + std::to_string(i); 103 } 104 std::string new_log = android::base::StringPrintf("%s.%d", last_log_file, i+1); 105 // Ignore errors if old_log doesn't exist. 106 rename(old_log.c_str(), new_log.c_str()); 107 108 std::string old_kmsg = android::base::StringPrintf("%s", last_kmsg_file); 109 if (i > 0) { 110 old_kmsg += "." + std::to_string(i); 111 } 112 std::string new_kmsg = android::base::StringPrintf("%s.%d", last_kmsg_file, i+1); 113 rename(old_kmsg.c_str(), new_kmsg.c_str()); 114 } 115 } 116