1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
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
25 static constexpr int FILE_MODE = 0644;
26
~BPFLogReader()27 BPFLogReader::~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
MakeUnique(const std::string & logFile)43 std::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
GetLogFileName() const61 std::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
OpenLogFile(const std::string & logFile)84 int 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
EnableTracePipe() const113 int 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
OpenTracePipe()131 int 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
MoveBPFLog()140 int 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 }