1 /*
2 * Copyright (c) 2021 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 "volume/process.h"
17
18 #include <csignal>
19 #include <dirent.h>
20 #include <unistd.h>
21
22 #include "storage_service_errno.h"
23 #include "storage_service_log.h"
24 #include "utils/string_utils.h"
25
26 using namespace std;
27
28 namespace OHOS {
29 namespace StorageDaemon {
Process(std::string path)30 Process::Process(std::string path)
31 {
32 path_ = path;
33 }
34
GetPids()35 std::unordered_set<pid_t> Process::GetPids()
36 {
37 return pids_;
38 }
39
GetPath()40 std::string Process::GetPath()
41 {
42 return path_;
43 }
44
Readlink(std::string path)45 std::string Process::Readlink(std::string path)
46 {
47 int len = 0;
48 int size = 0;
49 int growlen = 64;
50 std::string buf;
51
52 do {
53 size += growlen;
54 buf.assign(std::string(size, '\0'));
55 len = readlink(path.c_str(), buf.data(), size);
56 if (len == -1) {
57 return "";
58 }
59 } while (size <= len);
60
61 return buf;
62 }
63
CheckSubDir(std::string subdir)64 bool Process::CheckSubDir(std::string subdir)
65 {
66 const char *p = path_.c_str();
67 const char *q = subdir.c_str();
68
69 while (*p != '\0' && *q != '\0') {
70 if (*p != *q) {
71 return false;
72 }
73 p++;
74 q++;
75 }
76
77 if (*p == '\0' && *q == '\0') {
78 return true;
79 }
80
81 if (*p == '\0' && *q == '/') {
82 return true;
83 }
84
85 return false;
86 }
87
CheckMaps(std::string pidPath)88 bool Process::CheckMaps(std::string pidPath)
89 {
90 char *buf = nullptr;
91 size_t lineLen = 0;
92 std::string line;
93 auto path = StringPrintf("%s/maps", pidPath.c_str());
94 FILE *file = fopen(path.c_str(), "r");
95 if (file == nullptr) {
96 return false;
97 }
98
99 while (getline(&buf, &lineLen, file) > 0) {
100 line = buf;
101 std::string::size_type pos = line.find('/');
102 if (pos != line.npos) {
103 line = line.substr(pos);
104 if (CheckSubDir(line)) {
105 LOGI("Found map in %{public}s", pidPath.c_str());
106 (void)fclose(file);
107 free(buf);
108 buf = nullptr;
109 return true;
110 }
111 }
112 }
113
114 (void)fclose(file);
115 free(buf);
116 buf = nullptr;
117 return false;
118 }
119
CheckSymlink(std::string path)120 bool Process::CheckSymlink(std::string path)
121 {
122 std::string link = Readlink(path);
123 if (!link.empty() && CheckSubDir(link)) {
124 return true;
125 }
126 return false;
127 }
128
CheckFds(std::string pidPath)129 bool Process::CheckFds(std::string pidPath)
130 {
131 struct dirent *dirEntry;
132 auto path = StringPrintf("%s/fd", pidPath.c_str());
133 DIR *dir = opendir(path.c_str());
134 if (dir == nullptr) {
135 return E_ERR;
136 }
137
138 while ((dirEntry = readdir(dir)) != nullptr) {
139 if (dirEntry->d_type != DT_LNK) continue;
140 if (CheckSymlink(path + "/" + dirEntry->d_name)) {
141 (void)closedir(dir);
142 return true;
143 }
144 }
145
146 (void)closedir(dir);
147 return false;
148 }
149
UpdatePidByPath()150 int32_t Process::UpdatePidByPath()
151 {
152 struct dirent *dirEntry;
153 DIR *dir = opendir("/proc");
154 if (dir == nullptr) {
155 return E_ERR;
156 }
157
158 while ((dirEntry = readdir(dir)) != nullptr) {
159 if (dirEntry->d_type != DT_DIR) continue;
160 pid_t pid = atoi(dirEntry->d_name);
161 if (pid > 0 && pid != getprocpid()) {
162 std::string pidPath = StringPrintf("/proc/%d", pid);
163 if (CheckMaps(pidPath)
164 || CheckSymlink(pidPath + "/cwd")
165 || CheckSymlink(pidPath + "/root")
166 || CheckSymlink(pidPath + "/exe")) {
167 pids_.insert(pid);
168 }
169 }
170 }
171
172 (void)closedir(dir);
173 return E_OK;
174 }
175
KillProcess(int signal)176 void Process::KillProcess(int signal)
177 {
178 if (signal == 0) {
179 return;
180 }
181
182 for (const auto& pid : pids_) {
183 LOGI("KILL PID %{public}d", pid);
184 kill(pid, signal);
185 }
186 pids_.clear();
187 }
188 } // StorageDaemon
189 } // OHOS
190