/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "recovery-refresh" // // Strictly to deal with reboot into system after OTA, then // reboot while in system before boot complete landing us back // into recovery to continue with any mitigations with retained // log history. This simply refreshes the pmsg files from // the last pmsg file contents. // // Usage: // recovery-refresh [--force-rotate|--rotate] // // All file content representing in the recovery/ directory stored in // /sys/fs/pstore/pmsg-ramoops-0 in logger format that reside in the // LOG_ID_SYSTEM buffer at ANDROID_LOG_INFO priority or higher is // refreshed into /dev/pmsg0. This ensures that an unexpected reboot // before recovery-persist is run will still contain the associated // pmsg Android Logger content. // // --force-rotate recovery/last_kmsg and recovery.last_log files are // rotated with . suffixes upwards. // --rotate rotated only if rocovery/last_msg or recovery/last_log // exist, otherwise perform 1:1 refresh. // #include #include #include /* Android Log Priority Tags */ #include /* Android Log packet format */ #include /* private pmsg functions */ static const char LAST_KMSG_FILE[] = "recovery/last_kmsg"; static const char LAST_LOG_FILE[] = "recovery/last_log"; static ssize_t logbasename( log_id_t /* logId */, char /* prio */, const char *filename, const char * /* buf */, size_t len, void *arg) { if (strstr(LAST_KMSG_FILE, filename) || strstr(LAST_LOG_FILE, filename)) { bool *doRotate = reinterpret_cast(arg); *doRotate = true; } return len; } static ssize_t logrotate( log_id_t logId, char prio, const char *filename, const char *buf, size_t len, void *arg) { bool *doRotate = reinterpret_cast(arg); if (!*doRotate) { return __android_log_pmsg_file_write(logId, prio, filename, buf, len); } std::string name(filename); size_t dot = name.find_last_of("."); std::string sub = name.substr(0, dot); if (!strstr(LAST_KMSG_FILE, sub.c_str()) && !strstr(LAST_LOG_FILE, sub.c_str())) { return __android_log_pmsg_file_write(logId, prio, filename, buf, len); } // filename rotation if (dot == std::string::npos) { name += ".1"; } else { std::string number = name.substr(dot + 1); if (!isdigit(number.data()[0])) { name += ".1"; } else { unsigned long long i = std::stoull(number); name = sub + "." + std::to_string(i + 1); } } return __android_log_pmsg_file_write(logId, prio, name.c_str(), buf, len); } int main(int argc, char **argv) { static const char filter[] = "recovery/"; static const char force_rotate_flag[] = "--force-rotate"; static const char rotate_flag[] = "--rotate"; ssize_t ret; bool doRotate = false; // Take last pmsg contents and rewrite it to the current pmsg session. if ((argc <= 1) || !argv[1] || (((doRotate = strcmp(argv[1], rotate_flag))) && strcmp(argv[1], force_rotate_flag))) { doRotate = false; } else if (!doRotate) { // Do we need to rotate? __android_log_pmsg_file_read( LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logbasename, &doRotate); } // Take action to refresh pmsg contents ret = __android_log_pmsg_file_read( LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter, logrotate, &doRotate); return (ret < 0) ? ret : 0; }