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