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