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 
logbasename(log_id_t,char,const char * filename,const char *,size_t len,void * arg)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 
logrotate(log_id_t logId,char prio,const char * filename,const char * buf,size_t len,void * arg)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.
rotate_logs(const char * last_log_file,const char * last_kmsg_file)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