Ddengrenqipart5
83e18a97创建于 3月26日历史提交
/*
 * Copyright (c) 2021-2026 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "volume/process.h"

#include <csignal>
#include <dirent.h>
#include <unistd.h>

#include "storage_service_errno.h"
#include "storage_service_log.h"
#include "utils/string_utils.h"

using namespace std;

namespace OHOS {
namespace StorageDaemon {
Process::Process(std::string path)
{
    path_ = path;
    LOGD("[L4:Process] Constructor: path=%{public}s", path.c_str());
}

std::string Process::GetPath()
{
    return path_;
}

std::string Process::Readlink(std::string path)
{
    int len = 0;
    int size = 0;
    int growlen = 64;
    std::string buf;

    do {
        size += growlen;
        buf.assign(std::string(size, '\0'));
        len = readlink(path.c_str(), buf.data(), size);
        if (len == -1) {
            LOGE("[L4:Process] Readlink: failed, path=%{public}s, errno=%{public}d", path.c_str(), errno);
            return "";
        }
    } while (size <= len);

    return buf;
}

bool Process::CheckSubDir(std::string subdir)
{
    const char *p = path_.c_str();
    const char *q = subdir.c_str();

    while (*p != '\0' && *q != '\0') {
        if (*p != *q) {
            return false;
        }
        p++;
        q++;
    }

    if (*p == '\0' && *q == '\0') {
        return true;
    }

    if (*p == '\0' && *q == '/') {
        return true;
    }

    return false;
}

bool Process::CheckMaps(std::string pidPath)
{
    char *buf = nullptr;
    size_t lineLen = 0;
    std::string line;
    auto path = StringPrintf("%s/maps", pidPath.c_str());
    FILE *file = fopen(path.c_str(), "r");
    if (file == nullptr) {
        LOGE("[L4:Process] CheckMaps: open failed, path=%{public}s, errno=%{public}d", path.c_str(), errno);
        return false;
    }

    while (getline(&buf, &lineLen, file) > 0) {
        line = buf;
        std::string::size_type pos = line.find('/');
        if (pos != line.npos) {
            line = line.substr(pos);
            if (CheckSubDir(line)) {
                LOGI("[L4:Process] CheckMaps: found map in pidPath=%{public}s", pidPath.c_str());
                (void)fclose(file);
                free(buf);
                buf = nullptr;
                return true;
            }
        }
    }

    (void)fclose(file);
    free(buf);
    buf = nullptr;
    return false;
}

bool Process::CheckSymlink(std::string path)
{
    std::string link = Readlink(path);
    if (!link.empty() && CheckSubDir(link)) {
        return true;
    }
    return false;
}

bool Process::CheckFds(std::string pidPath)
{
    struct dirent *dirEntry;
    auto path = StringPrintf("%s/fd", pidPath.c_str());
    DIR *dir = opendir(path.c_str());
    if (dir == nullptr) {
        LOGE("[L4:Process] CheckFds: opendir failed, path=%{public}s, errno=%{public}d", path.c_str(), errno);
        return false;
    }

    while ((dirEntry = readdir(dir)) != nullptr) {
        if (dirEntry->d_type != DT_LNK) continue;
        if (CheckSymlink(path + "/" + dirEntry->d_name)) {
            (void)closedir(dir);
            return true;
        }
    }

    (void)closedir(dir);
    return false;
}

int32_t Process::UpdatePidAndKill(int signal)
{
    LOGD("[L4:Process] UpdatePidByPath: >>> ENTER <<< path=%{public}s", path_.c_str());
    if (signal == 0) {
        return E_OK;
    }

    struct dirent *dirEntry;
    DIR *dir = opendir("/proc");
    if (dir == nullptr) {
        LOGE("[L4:Process] UpdatePidByPath: <<< EXIT FAILED <<< opendir /proc failed, errno=%{public}d", errno);
        return E_ERR;
    }

    while ((dirEntry = readdir(dir)) != nullptr) {
        if (dirEntry->d_type != DT_DIR) continue;
        pid_t pid = atoi(dirEntry->d_name);
        if (pid > 0 && pid != getprocpid()) {
            std::string pidPath = StringPrintf("/proc/%d", pid);
            if (CheckMaps(pidPath)
                || CheckSymlink(pidPath + "/cwd")
                || CheckSymlink(pidPath + "/root")
                || CheckSymlink(pidPath + "/exe")) {
                LOGI("KILL PID %{public}d immediately", pid);
                kill(pid, signal);
            }
        }
    }

    (void)closedir(dir);
    LOGD("[L4:Process] UpdatePidByPath: <<< EXIT SUCCESS <<< ");
    return E_OK;
}
} // StorageDaemon
} // OHOS