1/* 2 * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include <ctime> 17#include <sstream> 18#include <sys/time.h> 19#include <fcntl.h> 20#include <poll.h> 21#include <unistd.h> 22 23#include "bpf_log_reader.h" 24 25static constexpr int FILE_MODE = 0644; 26 27BPFLogReader::~BPFLogReader() 28{ 29 Stop(); 30 if (worker_.joinable()) { 31 worker_.join(); 32 } 33 if (ifd_ >= 0) { 34 close(ifd_); 35 ifd_ = -1; 36 } 37 if (ofd_ >= 0) { 38 close(ofd_); 39 ofd_ = -1; 40 } 41} 42 43std::unique_ptr<BPFLogReader> BPFLogReader::MakeUnique(const std::string& logFile) 44{ 45 std::unique_ptr<BPFLogReader> logReader {new(std::nothrow) BPFLogReader {}}; 46 if (logReader == nullptr) { 47 return nullptr; 48 } 49 if (logReader->EnableTracePipe() != 0) { 50 return nullptr; 51 } 52 if (logReader->OpenTracePipe() != 0) { 53 return nullptr; 54 } 55 if (logReader->OpenLogFile(logFile) != 0) { 56 return nullptr; 57 } 58 return logReader; 59} 60 61std::string BPFLogReader::GetLogFileName() const 62{ 63 struct timeval timer; 64 gettimeofday(&timer, nullptr); 65 time_t now = (time_t) timer.tv_sec; 66 struct tm* tmPtr {nullptr}; 67 tmPtr = localtime(&now); 68 if (tmPtr == nullptr) { 69 return ""; 70 } 71 std::stringstream ss; 72 constexpr int yearStart {1900}; 73 constexpr int monthStart {1}; 74 ss << "/data/local/tmp/"; 75 ss << std::to_string(tmPtr->tm_year + yearStart) << "."; 76 ss << std::to_string(tmPtr->tm_mon + monthStart) << "."; 77 ss << std::to_string(tmPtr->tm_mday) << "_"; 78 ss << std::to_string(tmPtr->tm_hour) << "."; 79 ss << std::to_string(tmPtr->tm_min) << "."; 80 ss << std::to_string(tmPtr->tm_sec) << ".bpf.log"; 81 return ss.str(); 82} 83 84int BPFLogReader::OpenLogFile(const std::string& logFile) 85{ 86 if (logFile.compare("stdout") == 0) { 87 if (fcntl(STDOUT_FILENO, F_GETFL)) { 88 ofd_ = open("/dev/stdout", O_WRONLY); 89 } else { 90 ofd_ = STDOUT_FILENO; 91 } 92 if (ofd_ < 0) { 93 return -1; 94 } 95 return 0; 96 } 97 auto fileName = GetLogFileName(); 98 if (fileName.length() == 0) { 99 return -1; 100 } 101 ofd_ = open(fileName.c_str(), O_WRONLY | O_CREAT, FILE_MODE); 102 if (ofd_ < 0) { 103 return -1; 104 } 105 unlink(logFile.c_str()); 106 if (link(fileName.c_str(), logFile.c_str()) != 0) { 107 return -1; 108 } 109 110 return 0; 111} 112 113int BPFLogReader::EnableTracePipe() const 114{ 115 int fd = open(confPath_.c_str(), O_WRONLY); 116 if (fd < 0) { 117 return -1; 118 } 119 if (ftruncate(fd, 0) != 0) { 120 } 121 char c {'1'}; 122 int ret = write(fd, &c, sizeof(c)); 123 if (ret != sizeof(c)) { 124 return -1; 125 } 126 close(fd); 127 128 return 0; 129} 130 131int BPFLogReader::OpenTracePipe() 132{ 133 ifd_ = open(pipePath_.c_str(), O_RDONLY | O_NONBLOCK); 134 if (ifd_ < 0) { 135 return -1; 136 } 137 return 0; 138} 139 140int BPFLogReader::MoveBPFLog() 141{ 142 constexpr size_t bufSize {1024}; 143 char buffer[bufSize]; 144 while (true) { 145 struct pollfd fds; 146 fds.fd = ifd_; 147 fds.events = POLLIN; 148 constexpr int timeout {10}; 149 constexpr nfds_t nfds {1}; 150 int ret = poll(&fds, nfds, timeout); 151 if (stop_ or ret == -1) { 152 break; 153 } 154 if (ret == nfds) { 155 ret = read(ifd_, buffer, sizeof(buffer)); 156 if (ret <= 0) { 157 break; 158 } 159 ret = write(ofd_, buffer, ret); 160 if (ret <= 0) { 161 break; 162 } 163 } 164 } 165 return 0; 166}