/* common/KMExecer.h
 *
 * Copyright (C) 2023 OpenKylin, Inc
 */

#ifndef KMEXECER_H
#define KMEXECER_H

#include <map>
#include <set>
#include <string>
#include <vector>
#include <filesystem>

#include "config.h"
#include "KMCommonTypePrivate.h"

using namespace std;
namespace fs = std::filesystem;

/**
 * @brief : 封装沙箱或容器
 */
class KMExecer
{
public:
    KMExecer();
    KMExecer(const KMExecer &other);
    KMExecer(const std::map<std::string, std::string> &envs);
    virtual ~KMExecer();

    void run(bool share_space = true, bool block = true);
    void setProgress(const string &progress);
    string getProgress() const
    {
        return m_progress;
    }

    void insertArg(const string &arg);
    void addArg(const string &arg);
    void addArgs(const vector<string> &args);
    void addArgsDataFd(const std::string &op, int fd, const std::string &pathOptional);
    void removeRangeArgs(int start, int end);
    void insertArg(int pos, const std::string &arg);

    const vector<string> &getArgs() const
    {
        return m_args;
    }
    const vector<int> &getFds() const
    {
        return m_fds;
    }
    const map<string, string> &getEnvs() const
    {
        return m_envs;
    }

    bool addLdSoConfig();
    void bindDev(const string &src, const string &dest);
    void bindFd(int fd, const string &dest);
    void bindMount(const string &src, const string &dest, bool readOnly = false, bool _try = false);
    bool bindMountData(const string &name, const string &str, const string &dest);
    void addFd(int fd)
    {
        m_fds.push_back(fd);
    }
    void syncFd(int fd);
    void lockFile(const string &file);
    void symlink(const string &src, const string &dest);
    void tmpfs(const string &target);

    void addRuntimeDirMember(const string &member)
    {
        m_runtimeDirMember.push_back(member);
    }
    void addNoinheritFd(int fd)
    {
        m_noinheritFds.push_back(fd);
    }

    void env2Args();
    void packingArgs(int start = 0, int end = -1, bool oneArg = false);

    void addEnv(const string &key, const string &val);
    void addEnvs(const map<string, string> &envs);
    void removeEnv(const string &key);
    void clearEnvs()
    {
        m_envs.clear();
    }

    void addBindArg(const std::string &type, const std::string &src, const std::string &dest);

    bool empty() const
    {
        // 默认第一个参数设置了kaiming-box，所以必需大于1才是非空
        return m_envs.size() <= 1;
    }

    const std::vector<std::string> &getRuntimeDirMember() const
    {
        return m_runtimeDirMember;
    }

    int execvpe();

#ifdef ENABLE_SECCOMP
    bool setupSeccomp(const std::string &arch, unsigned long allowedPersonality, KMRunFlags runFlags, std::string &errMsg);
#endif

private:
    void init();
    void allowFD();
    bool buffer2Tmpfile(const string &name, const char *str, int len = -1);
    void setEnvArgs(const string &name, const string &value);

    int m_argsFd;
    string m_progress;
    vector<int> m_fds;
    vector<int> m_noinheritFds; /* Just keep these open while the kaiming-box lives */
    set<string> m_setSymlinks;
    vector<string> m_args;
    vector<string> m_runtimeDirMember;
    map<string, string> m_envs;

    //Just use at last invoke execvpe, set the argv
    std::vector<const char *> m_execvpeArgs;
};

#endif // KMEXECER_H
