Line data Source code
1 : /**
2 : * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "tsd_util_func.h"
12 : #include <iostream>
13 : #include <fstream>
14 : #include <algorithm>
15 : #include <cctype>
16 : #include <csignal>
17 : #include <cstring>
18 : #include <dirent.h>
19 : #include <dlfcn.h>
20 : #include <semaphore.h>
21 : #include <thread>
22 : #include <cerrno>
23 : #include <sys/wait.h>
24 : #include <regex.h>
25 : #include <climits>
26 : #include <cstdlib>
27 : #include <sstream>
28 : #include <iomanip>
29 : #include "basic_define.h"
30 : #include "weak_ascend_hal.h"
31 : #include "tsd_sha256.h"
32 : #include "tsd_log.h"
33 :
34 : namespace {
35 : constexpr int32_t SYSTE_EXECUTE_CMD_ERROR = 127; // 与system实现保持一致
36 : // min number of vDeviceId
37 : constexpr const uint32_t VDEVICE_MIN_CPU_NUM = 32U;
38 : // max number of vDeviceId
39 : constexpr const uint32_t VDEVICE_MAX_CPU_NUM = 64U;
40 : } // namespace
41 :
42 : namespace tsd {
43 136 : void Trim(std::string& str)
44 : {
45 136 : if (str.empty()) {
46 2 : return;
47 : }
48 134 : (void)str.erase(static_cast<size_t>(0), str.find_first_not_of(" "));
49 134 : (void)str.erase(str.find_last_not_of(" ") + static_cast<size_t>(1));
50 : }
51 :
52 26 : void TrimWhitespace(std::string& str)
53 : {
54 56 : auto isSpace = [](unsigned char c) { return std::isspace(c) != 0; };
55 29 : while (!str.empty() && isSpace(static_cast<unsigned char>(str.back()))) {
56 3 : str.pop_back();
57 : }
58 26 : size_t pos = 0U;
59 29 : while (pos < str.size() && isSpace(static_cast<unsigned char>(str[pos]))) {
60 3 : ++pos;
61 : }
62 26 : if (pos > 0U) {
63 2 : (void)str.erase(0U, pos);
64 : }
65 26 : }
66 :
67 32 : std::vector<std::string> SplitByChar(const std::string& s, char sep)
68 : {
69 32 : std::vector<std::string> tokens;
70 32 : std::string cur;
71 181 : for (char c : s) {
72 149 : if (c == sep) {
73 57 : tokens.emplace_back(std::move(cur));
74 57 : cur.clear();
75 : } else {
76 92 : cur.push_back(c);
77 : }
78 : }
79 32 : tokens.emplace_back(std::move(cur));
80 32 : return tokens;
81 32 : }
82 :
83 40 : int32_t CompareSegmentNumeric(const std::string& a, const std::string& b)
84 : {
85 80 : auto allDigit = [](const std::string& s) {
86 160 : return !s.empty() &&
87 241 : std::all_of(s.begin(), s.end(), [](char c) { return std::isdigit(static_cast<unsigned char>(c)) != 0; });
88 : };
89 40 : const bool aDigit = allDigit(a);
90 40 : const bool bDigit = allDigit(b);
91 40 : if (aDigit && bDigit) {
92 37 : std::string aa = a;
93 37 : std::string bb = b;
94 37 : size_t pa = aa.find_first_not_of('0');
95 37 : size_t pb = bb.find_first_not_of('0');
96 44 : aa = (pa == std::string::npos) ? "0" : aa.substr(pa);
97 44 : bb = (pb == std::string::npos) ? "0" : bb.substr(pb);
98 37 : if (aa.size() != bb.size()) {
99 1 : return (aa.size() < bb.size()) ? -1 : 1;
100 : }
101 36 : if (aa == bb) {
102 29 : return 0;
103 : }
104 7 : return (aa < bb) ? -1 : 1;
105 37 : }
106 3 : if (a == b) {
107 1 : return 0;
108 : }
109 2 : return (a < b) ? -1 : 1;
110 : }
111 :
112 14 : uint64_t CalFileSize(const std::string& filePath)
113 : {
114 14 : struct stat st = {};
115 14 : const auto ret = lstat(filePath.c_str(), &st);
116 14 : if (ret != 0) {
117 13 : TSD_RUN_WARN(
118 : "Getting the file stat was not successful, ret=%d, path=%s, reason=%s", ret, filePath.c_str(),
119 : SafeStrerror().c_str());
120 13 : return 0UL;
121 : }
122 :
123 1 : return st.st_size;
124 : }
125 :
126 833 : bool ValidateStr(const std::string& str, const std::string& mode)
127 : {
128 : regex_t reg;
129 833 : int32_t ret = regcomp(®, mode.c_str(), REG_EXTENDED | REG_NOSUB);
130 833 : if (ret != 0) {
131 0 : return false;
132 : }
133 833 : ret = regexec(®, str.c_str(), static_cast<size_t>(0), nullptr, 0);
134 833 : if (ret != 0) {
135 545 : regfree(®);
136 545 : return false;
137 : }
138 :
139 288 : regfree(®);
140 288 : return true;
141 : }
142 :
143 43 : void GetScheduleEnv(const char_t* const envName, std::string& envValue)
144 : {
145 43 : const size_t envValueMaxLen = 1024UL * 1024UL;
146 43 : if (envName == nullptr) {
147 1 : return;
148 : }
149 : try {
150 42 : const char_t* const envTemp = std::getenv(envName);
151 42 : if ((envTemp == nullptr) || (strnlen(envTemp, envValueMaxLen) >= envValueMaxLen)) {
152 3 : TSD_WARN("Get env[%s] failed", envName);
153 3 : return;
154 : }
155 39 : envValue = envTemp;
156 0 : } catch (std::exception& e) {
157 0 : TSD_ERROR("get env failed:[%s]", e.what());
158 0 : }
159 : }
160 :
161 4 : bool GetFlagFromEnv(const char_t* const envStr, const char_t* const envValue)
162 : {
163 4 : std::string isFlag;
164 4 : GetScheduleEnv(envStr, isFlag);
165 4 : if (!isFlag.empty()) {
166 2 : if (isFlag == envValue) {
167 1 : return true;
168 : }
169 : }
170 3 : return false;
171 4 : }
172 :
173 172 : bool IsFpgaEnv()
174 : {
175 172 : static const bool isFpga = GetFlagFromEnv("DATAMASTER_RUN_MODE", "1");
176 172 : return isFpga;
177 : }
178 :
179 112 : bool CheckRealPath(const std::string& inputPath)
180 : {
181 112 : if (inputPath.empty()) {
182 0 : TSD_RUN_INFO("Input path is empty");
183 0 : return false;
184 : }
185 112 : if (inputPath.length() >= static_cast<size_t>(PATH_MAX)) {
186 0 : TSD_RUN_INFO("Input path must less than [%d]", PATH_MAX);
187 0 : return false;
188 : }
189 112 : std::unique_ptr<char_t[]> path(new (std::nothrow) char_t[PATH_MAX]);
190 112 : if (path == nullptr) {
191 0 : TSD_RUN_WARN("Alloc memory for path failed.");
192 0 : return false;
193 : }
194 :
195 112 : const auto eRet = memset_s(path.get(), PATH_MAX, 0, PATH_MAX);
196 112 : if (eRet != EOK) {
197 0 : TSD_RUN_WARN("Mem set error, ret= [%d]", eRet);
198 0 : return false;
199 : }
200 :
201 112 : if (realpath(inputPath.data(), path.get()) == nullptr) {
202 103 : TSD_RUN_WARN("Format to realpath failed, inputPath is [%s]", inputPath.c_str());
203 103 : return false;
204 : }
205 9 : std::string normalizedPath(path.get());
206 9 : if (normalizedPath[normalizedPath.size() - static_cast<size_t>(1)] != '/') {
207 9 : (void)normalizedPath.append("/");
208 : }
209 9 : if (strncmp(normalizedPath.c_str(), inputPath.c_str(), inputPath.length()) != 0) {
210 0 : TSD_RUN_INFO("Invalid path [%s], should be [%s]", inputPath.c_str(), normalizedPath.c_str());
211 0 : return false;
212 : }
213 9 : return true;
214 112 : }
215 :
216 14 : bool CheckValidatePath(const std::string& path)
217 : {
218 14 : const std::string pathPattern = "^[0-9a-zA-Z\\/\\_\\.\\-]+$";
219 28 : return ValidateStr(path, pathPattern);
220 14 : }
221 :
222 8 : int32_t TsdExecuteCmd(const std::string& cmd)
223 : {
224 8 : if (cmd.empty()) {
225 0 : return -1;
226 : }
227 :
228 8 : int32_t status = 0;
229 8 : const int32_t pid = vfork();
230 16 : if (pid < 0) {
231 0 : status = -1;
232 16 : } else if (pid == 0) {
233 8 : (void)execl("/bin/sh", "sh", "-c", cmd.c_str(), nullptr);
234 0 : _exit(SYSTE_EXECUTE_CMD_ERROR);
235 : } else {
236 8 : while (waitpid(pid, &status, 0) < 0) {
237 0 : if (errno != EINTR) {
238 0 : status = -1;
239 0 : break;
240 : }
241 : }
242 : }
243 :
244 8 : return status;
245 : }
246 :
247 8 : int32_t PackSystem(const char_t* const cmdLine)
248 : {
249 8 : const sighandler_t oldHandler = signal(SIGCHLD, nullptr);
250 : // system()函数失败是由于“ No child processes”
251 : // 如果SIGCHLD信号行为被设置为SIG_IGN时,waitpid()函数有可能因为找不到子进程而报ECHILD错误
252 : // 是因为system()函数依赖了系统的一个特性,那就是内核初始化进程时对SIGCHLD信号的处理方式为SIG_DFL
253 8 : const int32_t ret = TsdExecuteCmd(cmdLine);
254 8 : TSD_INFO(
255 : "[TSDaemon] PackSystem cmd: [%s], result: [%d], errno[%d], reason[%s].", cmdLine, ret, errno,
256 : SafeStrerror().c_str());
257 8 : (void)signal(SIGCHLD, oldHandler);
258 8 : return ret;
259 : }
260 :
261 52 : static bool IsTinyRuntime()
262 : {
263 : #ifdef TINY_RUNTIME
264 : return true;
265 : #else
266 52 : return false;
267 : #endif
268 : }
269 :
270 : /**
271 : * int strerror_r(int errnum, char buf[.buflen], size_t buflen); POSIX
272 : * char *strerror_r(int errnum, char buf[.buflen], size_t buflen); GNU
273 : */
274 52 : std::string SafeStrerror()
275 : {
276 52 : const uint32_t errnoLen = 256U;
277 52 : char_t errBuf[errnoLen] = {};
278 52 : auto errorMsg = strerror_r(errno, &errBuf[0], errnoLen);
279 52 : if (IsTinyRuntime()) {
280 0 : if (errorMsg == 0) {
281 0 : errBuf[errnoLen - 1U] = '\0';
282 0 : return std::string(errBuf);
283 : }
284 : } else {
285 52 : const char_t* errorMsgStr = reinterpret_cast<char_t*>(errorMsg);
286 52 : if (errorMsgStr != nullptr) {
287 104 : return std::string(errorMsgStr);
288 : }
289 : }
290 0 : return "";
291 : }
292 :
293 24 : uint32_t CalcUniqueVfId(const uint32_t deviceId, const uint32_t vfId)
294 : {
295 24 : if (IsVfModeCheckedByDeviceId(deviceId)) {
296 1 : return deviceId;
297 : }
298 :
299 23 : if ((deviceId == 0U) || (vfId == 0U)) {
300 23 : return vfId;
301 : }
302 :
303 : static uint32_t maxNumSpDev = 0U;
304 0 : if ((&halGetDeviceVfMax != nullptr) && (maxNumSpDev == 0U)) {
305 0 : const auto retRes = halGetDeviceVfMax(deviceId, &maxNumSpDev);
306 0 : if ((retRes != DRV_ERROR_NONE) || (maxNumSpDev > DEVICE_MAX_SPLIT_NUM)) {
307 0 : TSD_ERROR("Failed to get device cat vf number, result[%d], max num[%u].", retRes, maxNumSpDev);
308 0 : return UINT32_MAX;
309 : }
310 : }
311 0 : return (maxNumSpDev * deviceId) + vfId;
312 : }
313 :
314 35 : bool TransStrToInt(const std::string& para, int32_t& value)
315 : {
316 : try {
317 35 : value = std::stoi(para);
318 14 : } catch (...) {
319 14 : return false;
320 14 : }
321 :
322 21 : return true;
323 : }
324 :
325 14 : void RemoveOneFile(const std::string& filePath)
326 : {
327 14 : if (filePath.empty()) {
328 4 : return;
329 : }
330 :
331 10 : if (access(filePath.c_str(), F_OK) != 0) {
332 8 : TSD_INFO("The file does not exist, no need to remove, path=%s", filePath.c_str());
333 8 : return;
334 : }
335 :
336 2 : const int32_t ret = remove(filePath.c_str());
337 2 : if (ret != 0) {
338 1 : TSD_RUN_WARN(
339 : "Removing the file was not successful, ret=%d, path=%s, reason=%s", ret, filePath.c_str(),
340 : SafeStrerror().c_str());
341 1 : return;
342 : }
343 :
344 1 : TSD_INFO("Remove file success, path=%s", filePath.c_str());
345 : }
346 :
347 3 : bool IsDirEmpty(const std::string& dirPath)
348 : {
349 3 : DIR* dir = opendir(dirPath.c_str());
350 3 : if (!dir) {
351 1 : return true;
352 : }
353 :
354 : struct dirent* entry;
355 2 : int count = 0;
356 :
357 6 : while ((entry = readdir(dir)) != nullptr) {
358 5 : if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
359 4 : continue;
360 : }
361 :
362 1 : count++;
363 1 : if (count > 0) {
364 1 : (void)closedir(dir);
365 1 : return false;
366 : }
367 : }
368 :
369 1 : (void)closedir(dir);
370 1 : return true;
371 : }
372 :
373 9 : std::string CalFileSha256HashValue(const std::string& filePath)
374 : {
375 9 : std::ifstream curFile(filePath, std::ios::binary);
376 9 : if (!curFile) {
377 2 : TSD_RUN_WARN("Opening file:%s was not successful, reason:%s", filePath.c_str(), SafeStrerror().c_str());
378 4 : return "";
379 : }
380 :
381 7 : std::stringstream fileBuffer;
382 7 : fileBuffer << curFile.rdbuf();
383 7 : std::string fileBinaryValue = fileBuffer.str();
384 : std::string hashHex =
385 7 : sha256::ComputeHexString(PtrToPtr<const char, const uint8_t>(fileBinaryValue.c_str()), fileBinaryValue.size());
386 7 : curFile.close();
387 7 : return hashHex;
388 9 : }
389 :
390 23 : bool IsCurrentVfMode(const uint32_t deviceId, const uint32_t vfId)
391 : {
392 23 : if ((IsVfModeCheckedByDeviceId(deviceId)) || (vfId > 0)) {
393 2 : return true;
394 : } else {
395 21 : return false;
396 : }
397 : }
398 :
399 3 : std::string ExtractSubString(const std::string& input, const std::string& begin, const std::string& end)
400 : {
401 3 : size_t pos = input.find(begin);
402 3 : if (pos == std::string::npos) {
403 2 : return "";
404 : }
405 2 : size_t left = pos + begin.length();
406 2 : size_t right = input.find(end, left);
407 2 : if (right == std::string::npos) {
408 0 : return "";
409 : }
410 2 : return input.substr(left, right - left);
411 : }
412 :
413 67 : bool IsVfModeCheckedByDeviceId(const uint32_t deviceId)
414 : {
415 67 : if ((deviceId >= VDEVICE_MIN_CPU_NUM) && (deviceId < VDEVICE_MAX_CPU_NUM)) {
416 4 : return true;
417 : } else {
418 63 : return false;
419 : }
420 : }
421 :
422 571 : std::string GetHostSoPath()
423 : {
424 571 : Dl_info info = {};
425 571 : if (dladdr(reinterpret_cast<void*>(drvHdcSendFile), &info) == 0) {
426 1 : TSD_INFO("Getting the host so path was not successful, reason[%s], errno[%d]", SafeStrerror().c_str(), errno);
427 2 : return "";
428 : }
429 570 : TSD_INFO("dli_fname[%s]", info.dli_fname);
430 570 : if (info.dli_fname == nullptr) {
431 2 : return "";
432 : }
433 569 : std::string path(info.dli_fname);
434 569 : const size_t pos = path.find_last_of('/');
435 569 : std::string hostSoPath;
436 569 : if (pos != std::string::npos) {
437 568 : hostSoPath = path.substr(0, pos + static_cast<size_t>(1));
438 : } else {
439 1 : hostSoPath = "./";
440 : }
441 569 : TSD_INFO("host so path[%s]", hostSoPath.c_str());
442 569 : return hostSoPath;
443 569 : }
444 : } // namespace tsd
|