1 /*
2 * Copyright (c) 2021-2025 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 "common_utils.h"
17
18 #include <cstdint>
19 #include <cstdio>
20 #include <dirent.h>
21 #include <fcntl.h>
22 #include <sstream>
23 #include <string>
24 #include <sys/wait.h>
25 #include <sys/syscall.h>
26 #include <unistd.h>
27 #include <vector>
28
29 #include "securec.h"
30 #include "time_util.h"
31
32 using namespace std;
33 namespace OHOS {
34 namespace HiviewDFX {
35 namespace CommonUtils {
36 namespace {
37 constexpr int32_t UID_TRANSFORM_DIVISOR = 200000;
GetProcessNameFromProcCmdline(int32_t pid)38 std::string GetProcessNameFromProcCmdline(int32_t pid)
39 {
40 std::string procCmdlinePath = "/proc/" + std::to_string(pid) + "/cmdline";
41 std::string procCmdlineContent = FileUtil::GetFirstLine(procCmdlinePath);
42 if (procCmdlineContent.empty()) {
43 return "";
44 }
45
46 size_t procNameStartPos = 0;
47 size_t procNameEndPos = procCmdlineContent.size();
48 for (size_t i = 0; i < procCmdlineContent.size(); i++) {
49 if (procCmdlineContent[i] == '/') {
50 // for the format '/system/bin/hiview' of the cmdline file
51 procNameStartPos = i + 1; // 1 for next char
52 } else if (procCmdlineContent[i] == '\0') {
53 // for the format 'hiview \0 3 \0 hiview' of the cmdline file
54 procNameEndPos = i;
55 break;
56 }
57 }
58 return procCmdlineContent.substr(procNameStartPos, procNameEndPos - procNameStartPos);
59 }
60
GetProcessNameFromProcStat(int32_t pid)61 std::string GetProcessNameFromProcStat(int32_t pid)
62 {
63 std::string procStatFilePath = "/proc/" + std::to_string(pid) + "/stat";
64 std::string procStatFileContent = FileUtil::GetFirstLine(procStatFilePath);
65 if (procStatFileContent.empty()) {
66 return "";
67 }
68 // for the format '40 (hiview) I ...'
69 auto procNameStartPos = procStatFileContent.find('(');
70 if (procNameStartPos == std::string::npos) {
71 return "";
72 }
73 procNameStartPos += 1; // 1: for '(' next char
74
75 auto procNameEndPos = procStatFileContent.find(')');
76 if (procNameEndPos == std::string::npos) {
77 return "";
78 }
79 if (procNameEndPos <= procNameStartPos) {
80 return "";
81 }
82 return procStatFileContent.substr(procNameStartPos, procNameEndPos - procNameStartPos);
83 }
84 }
85
GetProcNameByPid(pid_t pid)86 std::string GetProcNameByPid(pid_t pid)
87 {
88 std::string result;
89 char buf[BUF_SIZE_256] = {0};
90 (void)snprintf_s(buf, BUF_SIZE_256, BUF_SIZE_256 - 1, "/proc/%d/comm", pid);
91 FileUtil::LoadStringFromFile(std::string(buf, strlen(buf)), result);
92 auto pos = result.find_last_not_of(" \n\r\t");
93 if (pos == std::string::npos) {
94 return result;
95 }
96 result.erase(pos + 1);
97 return result;
98 }
99
GetProcFullNameByPid(pid_t pid)100 std::string GetProcFullNameByPid(pid_t pid)
101 {
102 std::string procName = GetProcessNameFromProcCmdline(pid);
103 if (procName.empty() && errno != ESRCH) { // ESRCH means 'no such process'
104 procName = GetProcessNameFromProcStat(pid);
105 }
106 return procName;
107 }
108
GetPidByName(const std::string & processName)109 pid_t GetPidByName(const std::string& processName)
110 {
111 pid_t pid = -1;
112 std::string cmd = "pidof " + processName;
113
114 FILE* fp = popen(cmd.c_str(), "r");
115 if (fp != nullptr) {
116 char buffer[BUF_SIZE_256] = {'\0'};
117 while (fgets(buffer, sizeof(buffer) - 1, fp) != nullptr) {}
118 std::istringstream istr(buffer);
119 istr >> pid;
120 pclose(fp);
121 }
122 return pid;
123 }
124
IsPidExist(pid_t pid)125 bool IsPidExist(pid_t pid)
126 {
127 std::string procDir = "/proc/" + std::to_string(pid);
128 return FileUtil::IsDirectory(procDir);
129 }
130
IsSpecificCmdExist(const std::string & fullPath)131 bool IsSpecificCmdExist(const std::string& fullPath)
132 {
133 return access(fullPath.c_str(), X_OK) == 0;
134 }
135
WriteCommandResultToFile(int fd,const std::string & cmd,const std::vector<std::string> & args)136 int WriteCommandResultToFile(int fd, const std::string &cmd, const std::vector<std::string> &args)
137 {
138 if (cmd.empty()) {
139 return -1;
140 }
141
142 pid_t pid = fork();
143 if (pid < 0) {
144 return -1;
145 } else if (pid == 0) {
146 // follow standard, although dup2 may handle the case of invalid oldfd
147 if (fd >= 0) {
148 dup2(fd, STDOUT_FILENO);
149 dup2(fd, STDIN_FILENO);
150 dup2(fd, STDERR_FILENO);
151 }
152
153 std::vector<char *> argv;
154 for (const auto &arg : args) {
155 argv.push_back(const_cast<char *>(arg.c_str()));
156 }
157 argv.push_back(0);
158 execv(cmd.c_str(), &argv[0]);
159 }
160
161 constexpr uint64_t maxWaitingTime = 120; // 120 seconds
162 uint64_t endTime = TimeUtil::GetSteadyClockTimeMs() + maxWaitingTime * TimeUtil::SEC_TO_MILLISEC;
163 while (endTime > TimeUtil::GetSteadyClockTimeMs()) {
164 int status = 0;
165 pid_t p = waitpid(pid, &status, WNOHANG);
166 if (p < 0) {
167 return -1;
168 }
169
170 if (p == pid) {
171 return WEXITSTATUS(status);
172 }
173 }
174
175 return -1;
176 }
177
GetTransformedUid(int32_t uid)178 int32_t GetTransformedUid(int32_t uid)
179 {
180 return uid / UID_TRANSFORM_DIVISOR;
181 }
182 }
183 } // namespace HiviewDFX
184 } // namespace OHOS
185