* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include "process_utils.h"
#include "base/err_msg.h"
#include <unistd.h>
#include <fstream>
#include <cstdlib>
#include <csignal>
#include <regex>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/socket.h>
#include "common/checker.h"
#include "common/debug/ge_log.h"
#include "graph_metadef/common/ge_common/util.h"
namespace ge {
namespace {
constexpr char_t kValidChars[] = "[A-Za-z\\d/_.-]+";
constexpr char_t kInvalidChars[] = "[^A-Za-z\\d/_.-]+";
}
pid_t ProcessUtils::Fork() {
return fork();
}
int32_t ProcessUtils::Execute(const std::string &path, char_t *const *argv) {
return execv(path.c_str(), argv);
}
Status ProcessUtils::System(const std::string &cmd, bool print_err) {
sighandler_t old_handler = signal(SIGCHLD, SIG_DFL);
GE_MAKE_GUARD(old_handler, [&old_handler]() { signal(SIGCHLD, old_handler); });
auto status = system(cmd.c_str());
if (status == -1) {
if (print_err) {
GELOGE(FAILED, "Failed to execute cmd.");
}
return FAILED;
}
if (WIFEXITED(status) && (WEXITSTATUS(status) == 0)) {
return SUCCESS;
}
if (print_err) {
GELOGE(FAILED, "Execute cmd result failed, ret = %d.", WEXITSTATUS(status));
}
return FAILED;
}
Status ProcessUtils::GetIpaddr(const std::string &name, std::string &ipaddr) {
auto socket_fd = mmSocket(AF_INET, SOCK_DGRAM, 0);
if (socket_fd == EN_ERROR) {
GELOGE(FAILED, "[Get][Fd] Get socket fd error.");
return FAILED;
}
const size_t kBufsize = 1024U;
char_t buf[kBufsize]{};
struct ifconf ifc;
ifc.ifc_len = kBufsize;
ifc.ifc_buf = buf;
mmIoctlBuf ioctl_buf;
ioctl_buf.inbuf = &ifc;
auto ret = mmIoctl(socket_fd, SIOCGIFCONF, &ioctl_buf);
if (ret != EN_OK) {
GELOGE(FAILED, "[Get][Ifconfig] Get ifconfig info error.");
return FAILED;
}
struct ifreq *ifr = reinterpret_cast<struct ifreq *>(buf);
for (size_t i = 0U; i < ifc.ifc_len / sizeof(struct ifreq); ++i) {
struct sockaddr_in *addr = reinterpret_cast<struct sockaddr_in *>(&(ifr->ifr_addr));
char_t ip[INET_ADDRSTRLEN]{};
auto addr_ret = inet_ntop(AF_INET, &(addr->sin_addr), ip, INET_ADDRSTRLEN);
GE_CHECK_NOTNULL(addr_ret);
std::string r_name = ifr->ifr_name;
if (r_name != name) {
ifr += 1;
continue;
}
ipaddr = ip;
GELOGI("[Get][Ip] Get ipaddr success, ifr name = %s, ip = %s.", ifr->ifr_name, ip);
return SUCCESS;
}
GELOGE(FAILED, "[Get][Ip] Get ipaddr failed, net name = %s", name.c_str());
return FAILED;
}
pid_t ProcessUtils::WaitPid(pid_t pid, int32_t *wstatus, int options) {
return waitpid(pid, wstatus, options);
}
Status ProcessUtils::DoMkdir(const char_t *tmp_dir_path, mmMode_t mode) {
if (mmAccess2(tmp_dir_path, M_F_OK) != EN_OK) {
const int32_t ret = mmMkdir(tmp_dir_path, mode);
if (ret != 0) {
auto create_errno = errno;
if (mmAccess2(tmp_dir_path, M_F_OK) != EN_OK) {
REPORT_INNER_ERR_MSG("E18888",
"Cannot create directory %s. Make sure the directory "
"exists and writable. errmsg:%s",
tmp_dir_path, GetErrorNumStr(create_errno).c_str());
GELOGE(FAILED, "Create directory %s failed, reason:%s. Make sure the "
"directory exists and writable.",
tmp_dir_path, GetErrorNumStr(create_errno).c_str());
return FAILED;
}
}
}
return SUCCESS;
}
Status ProcessUtils::CreateDir(const std::string &directory_path) {
constexpr auto mode = static_cast<uint32_t>(M_IRUSR | M_IWUSR | M_IXUSR);
return ProcessUtils::CreateDir(directory_path, mode);
}
Status ProcessUtils::CreateDir(const std::string &directory_path, uint32_t mode) {
if (directory_path.empty()) {
REPORT_INNER_ERR_MSG("E18888", "directory path is empty, check invalid");
GELOGE(FAILED, "[Check][Param] directory path is empty.");
return FAILED;
}
const auto dir_path_len = directory_path.length();
if (dir_path_len >= static_cast<size_t>(MMPA_MAX_PATH)) {
REPORT_PREDEFINED_ERR_MSG("E13002", std::vector<const char *>({"filepath", "size"}),
std::vector<const char *>({directory_path.c_str(), std::to_string(MMPA_MAX_PATH).c_str()}));
GELOGE(FAILED, "Path %s len is too long, it must be less than %d", directory_path.c_str(), MMPA_MAX_PATH);
return FAILED;
}
char_t tmp_dir_path[MMPA_MAX_PATH] = {};
const auto mkdir_mode = static_cast<mmMode_t>(mode);
for (size_t i = 0U; i < dir_path_len; i++) {
tmp_dir_path[i] = directory_path[i];
if ((tmp_dir_path[i] == '\\') || (tmp_dir_path[i] == '/')) {
GE_CHK_STATUS_RET(DoMkdir(&(tmp_dir_path[0U]), mkdir_mode), "Failed to mkdir");
}
}
return DoMkdir(directory_path.c_str(), mkdir_mode);
}
Status ProcessUtils::IsValidPath(const std::string &path) {
GE_CHK_BOOL_RET_STATUS((path.find("..") == std::string::npos),
FAILED,
"File path[%s] is invalid, include relative path.",
path.c_str());
std::regex e(kValidChars);
std::smatch sm;
GE_CHK_BOOL_RET_STATUS(std::regex_match(path, sm, e), FAILED,
"Path[%s] is invalid, please use a-z, A-Z, 0-9, _, - and /",
path.c_str());
return SUCCESS;
}
std::string ProcessUtils::NormalizePath(const std::string &path) {
std::regex e(kInvalidChars);
return std::regex_replace(path, e, "_");
}
}