feat: 初始代码

AM初始代码,迁移自gitlabwh

Log:
Task: https://pms.uniontech.com/task-view-108539.html
Influence:
Change-Id: I6096f97e5d68d13796ff5dc51d9858c0f40264a0
This commit is contained in:
tanfeng
2022-03-30 17:56:27 +08:00
parent 9414feb1f7
commit 0b22bb3adf
54 changed files with 3607 additions and 0 deletions

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2021-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "common.h"
namespace linglong {
namespace util {
std::string str_vec_join(const str_vec &vec, char sep)
{
if (vec.empty()) {
return "";
}
std::string s;
for (auto iterator = vec.begin(); iterator != std::prev(vec.end()); ++iterator) {
s += *iterator + sep;
}
s += vec.back();
return s;
}
str_vec str_spilt(const std::string &s, const std::string &sep)
{
str_vec vec;
size_t pos_begin = 0;
size_t pos_end = 0;
while ((pos_end = s.find(sep, pos_begin)) != std::string::npos) {
auto t = s.substr(pos_begin, pos_end - pos_begin);
if (!t.empty()) {
vec.push_back(t);
}
pos_begin = pos_end + sep.size();
}
auto t = s.substr(pos_begin, s.size() - pos_begin);
if (!t.empty()) {
vec.push_back(t);
}
return vec;
}
} // namespace util
} // namespace linglong

64
src/modules/util/common.h Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef LINGLONG_BOX_SRC_UTIL_COMMON_H_
#define LINGLONG_BOX_SRC_UTIL_COMMON_H_
#include <memory>
#include <cstring>
#include <cstdarg>
#include <vector>
#include <iostream>
#include <iterator>
namespace linglong {
namespace util {
typedef std::vector<std::string> str_vec;
str_vec str_spilt(const std::string &s, const std::string &sep);
std::string str_vec_join(const str_vec &vec, char sep);
inline std::string format(const std::string fmt, ...)
{
int n = ((int)fmt.size()) * 2;
std::unique_ptr<char[]> formatted;
va_list ap;
while (true) {
formatted.reset(new char[n]);
strcpy(&formatted[0], fmt.c_str());
va_start(ap, fmt);
int final_n = vsnprintf(&formatted[0], n, fmt.c_str(), ap);
va_end(ap);
if (final_n < 0 || final_n >= n)
n += abs(final_n - n + 1);
else
break;
}
return std::string {formatted.get()};
}
} // namespace util
} // namespace linglong
template<typename T>
std::ostream &operator<<(std::ostream &out, const std::vector<T> &v)
{
if (!v.empty()) {
out << '[';
std::copy(v.begin(), v.end(), std::ostream_iterator<T>(out, ", "));
out << "\b\b]";
}
return out;
}
#endif /* LINGLONG_BOX_SRC_UTIL_COMMON_H_ */

View File

@ -0,0 +1,126 @@
/*
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <pwd.h>
#include <unistd.h>
#include <grp.h>
#include <dirent.h>
#include <sys/stat.h>
#include "../logger.h"
#include "debug.h"
namespace linglong {
#define DUMP_DBG(func, line) (linglong::util::Logger(linglong::util::Logger::Debug, func, line))
void DumpIDMap()
{
logDbg() << "DumpIDMap Start -----------";
std::ifstream uidMap("/proc/self/uid_map");
for (std::string line; getline(uidMap, line);) {
logDbg() << "uid_map of pid:" << getpid() << line;
}
std::ifstream gidMap("/proc/self/gid_map");
for (std::string line; getline(gidMap, line);) {
logDbg() << "gid_map of pid:" << getpid() << line;
}
auto setgroupsPath = util::format("/proc/self/setgroups");
std::ifstream setgroupsFileRead(setgroupsPath);
std::string line;
std::getline(setgroupsFileRead, line);
logDbg() << "setgroups of pid:" << getpid() << line;
logDbg() << "DumpIDMap end -----------";
}
void DumpUidGidGroup()
{
logDbg() << "DumpUidGidGroup Start -----------";
// __uid_t uid = getuid(); // you can change this to be the uid that you want
//
// struct passwd *pw = getpwuid(uid);
// if (pw == NULL) {
// perror("getpwuid error: ");
// }
//
// int ngroups = 0;
//
// // this call is just to get the correct ngroups
// getgrouplist(pw->pw_name, pw->pw_gid, NULL, &ngroups);
// __gid_t groups[ngroups];
//
// // here we actually get the groups
// getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
//
// // example to print the groups name
// for (int i = 0; i < ngroups; i++) {
// struct group *gr = getgrgid(groups[i]);
// if (gr == NULL) {
// perror("getgrgid error: ");
// }
// printf("%s\n", gr->gr_name);
// }
logDbg() << "getuid" << getuid() << "geteuid" << geteuid();
logDbg() << "getgid" << getgid() << "getegid" << getegid();
const int groupSize = getgroups(0, NULL);
__gid_t list[groupSize + 1];
getgroups(groupSize, list);
std::string groupListStr;
for (int i = 0; i < groupSize; ++i) {
groupListStr += util::format("%d ", list[i]);
}
logDbg() << "getgroups size " << groupSize << ", list:" << groupListStr;
logDbg() << "DumpUidGidGroup end -----------";
}
void DumpFilesystem(const std::string &path, const char *func, int line)
{
if (nullptr == func) {
func = const_cast<char *>(__FUNCTION__);
}
DUMP_DBG(func, line) << "DumpFilesystem begin -----------" << path;
DIR *dir;
if ((dir = opendir(path.c_str())) != NULL) {
struct dirent *ent;
/* print all the files and directories within directory */
while ((ent = readdir(dir)) != NULL) {
DUMP_DBG(func, line) << path + "/" + ent->d_name;
}
closedir(dir);
} else {
/* could not open directory */
logErr() << linglong::util::errnoString() << errno;
return;
}
DUMP_DBG(func, line) << "DumpFilesystem end -----------" << path;
}
void DumpFileInfo(const std::string &path)
{
DumpFileInfo1(path, __FUNCTION__, __LINE__);
}
void DumpFileInfo1(const std::string &path, const char *func, int line)
{
struct stat st {
};
auto ret = lstat(path.c_str(), &st);
if (0 != ret) {
DUMP_DBG(func, line) << path << util::RetErrString(ret);
} else {
DUMP_DBG(func, line) << path << st.st_uid << st.st_gid << ((st.st_mode & S_IFMT) == S_IFDIR);
}
}
} // namespace linglong

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef LINGLONG_BOX_SRC_UTIL_DEBUG_DEBUG_H_
#define LINGLONG_BOX_SRC_UTIL_DEBUG_DEBUG_H_
#include <string>
namespace linglong {
#define DUMP_FILESYSTEM(path) DumpFilesystem(path, __FUNCTION__, __LINE__)
#define DUMP_FILE_INFO(path) DumpFileInfo1(path, __FUNCTION__, __LINE__)
void DumpIDMap();
void DumpUidGidGroup();
void DumpFilesystem(const std::string &path, const char *func = nullptr, int line = -1);
void DumpFileInfo(const std::string &path);
void DumpFileInfo1(const std::string &path, const char *func = nullptr, int line = -1);
} // namespace linglong
#endif /* LINGLONG_BOX_SRC_UTIL_DEBUG_DEBUG_H_ */

View File

@ -0,0 +1,182 @@
/*
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <sys/stat.h>
#include <string>
#include <climits>
#include <unistd.h>
#include "filesystem.h"
#include "logger.h"
namespace linglong {
namespace util {
namespace fs {
using namespace std;
bool create_directory(const path &p, __mode_t mode)
{
return mkdir(p.string().c_str(), mode);
}
bool create_directories(const path &p, __mode_t mode)
{
std::string fullPath;
for (const auto &e : p.components()) {
fullPath += "/" + e;
if (is_dir(fullPath)) {
continue;
}
auto ret = mkdir(fullPath.c_str(), mode);
if (0 != ret) {
logErr() << util::RetErrString(ret) << fullPath << mode;
return false;
}
}
return true;
}
bool is_dir(const std::string &s)
{
struct stat st {
};
if (0 != lstat(s.c_str(), &st)) {
return false;
}
switch (st.st_mode & S_IFMT) {
case S_IFDIR:
return true;
default:
return false;
}
}
bool exists(const std::string &s)
{
struct stat st {
};
if (0 != lstat(s.c_str(), &st)) {
return false;
}
return true;
}
path read_symlink(const path &p)
{
char buf[PATH_MAX];
if (readlink(p.string().c_str(), buf, sizeof(buf)) < 0) {
return p;
} else {
return path(string(buf));
}
}
file_status status(const path &p, std::error_code &ec)
{
file_type ft;
perms perm = no_perms;
struct stat st {
};
if (0 != lstat(p.string().c_str(), &st)) {
if (errno == ENOENT) {
ft = file_not_found;
} else {
ft = status_error;
}
return file_status(ft, perm);
}
// FIXME: perms
// https://www.boost.org/doc/libs/1_75_0/libs/filesystem/doc/reference.html#file_status
// int st_perm = st.st_mode & 0xFFFF;
// switch (st_perm) {
// case S_IRUSR:
// perm = owner_read;
// break;
// case S_IWUSR:
// case S_IXUSR:
// case S_IRWXU:
// case S_IRGRP:
// }
switch (st.st_mode & S_IFMT) {
case S_IFREG:
ft = regular_file;
break;
case S_IFDIR:
ft = directory_file;
break;
case S_IFLNK:
ft = symlink_file;
break;
case S_IFBLK:
ft = block_file;
break;
case S_IFCHR:
ft = character_file;
break;
case S_IFIFO:
ft = fifo_file;
case S_IFSOCK:
break;
default:
ft = type_unknown;
break;
}
return file_status(ft, perm);
}
file_status::file_status() noexcept
{
}
file_status::file_status(file_type ft, perms perms) noexcept
: ft(ft)
, p(perms)
{
}
file_status::file_status(const file_status &fs) noexcept
{
ft = fs.ft;
p = fs.p;
}
file_status &file_status::operator=(const file_status &fs) noexcept
{
ft = fs.ft;
p = fs.p;
return *this;
}
file_status::~file_status() noexcept = default;
file_type file_status::type() const noexcept
{
return ft;
}
perms file_status::permissions() const noexcept
{
return p;
}
} // namespace fs
} // namespace util
} // namespace linglong

View File

@ -0,0 +1,151 @@
/*
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef LINGLONG_BOX_SRC_UTIL_FILESYSTEM_H_
#define LINGLONG_BOX_SRC_UTIL_FILESYSTEM_H_
#include <vector>
#include <ostream>
#include <system_error>
#include "common.h"
namespace linglong {
namespace util {
namespace fs {
class path : public std::basic_string<char>
{
public:
explicit path(const std::string &s)
: p(util::str_spilt(s, "/"))
{
}
path &operator=(const std::string &s)
{
p = util::str_spilt(s, "/");
return *this;
}
path &operator=(const path &p1) = default;
bool operator==(const path &s) const { return this->p == s.p; }
bool operator!=(const path &s) const { return this->p != s.p; }
path operator/(const path &p1) const
{
auto np = *this;
std::copy(p1.p.begin(), p1.p.end(), back_inserter(np.p));
return np;
}
path operator/(const std::string &str) const { return operator/(path(str)); }
path parent_path() const
{
path pn(*this);
pn.p.pop_back();
return pn;
}
std::string string() const { return "/" + str_vec_join(p, '/'); }
str_vec components() const { return p; }
private:
friend std::ostream &operator<<(std::ostream &cout, path obj);
std::vector<std::string> p;
};
inline std::ostream &operator<<(std::ostream &cout, path obj)
{
for (auto const &s : obj.p) {
cout << "/" << s;
}
return cout;
}
bool create_directories(const path &p, __mode_t mode);
enum file_type {
status_error,
file_not_found,
regular_file,
directory_file,
symlink_file,
block_file,
character_file,
fifo_file,
socket_file,
reparse_file,
type_unknown
};
enum perms {
no_perms,
owner_read,
owner_write,
owner_exe,
owner_all,
group_read,
group_write,
group_exe,
group_all,
others_read,
others_write,
others_exe,
others_all,
all_all,
set_uid_on_exe,
set_gid_on_exe,
sticky_bit,
perms_mask,
perms_not_known,
add_perms,
remove_perms,
symlink_perms
};
class file_status
{
public:
// constructors
file_status() noexcept;
explicit file_status(file_type ft, perms p = perms_not_known) noexcept;
// compiler generated
file_status(const file_status &) noexcept;
file_status &operator=(const file_status &) noexcept;
~file_status() noexcept;
// observers
file_type type() const noexcept;
perms permissions() const noexcept;
private:
file_type ft;
perms p;
};
bool is_dir(const std::string &s);
bool exists(const std::string &s);
file_status status(const path &p, std::error_code &ec);
path read_symlink(const path &p);
} // namespace fs
} // namespace util
} // namespace linglong
#endif /* LINGLONG_BOX_SRC_UTIL_FILESYSTEM_H_ */

58
src/modules/util/json.h Normal file
View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef LINGLONG_BOX_SRC_UTIL_JSON_H_
#define LINGLONG_BOX_SRC_UTIL_JSON_H_
#define JSON_USE_IMPLICIT_CONVERSIONS 0
#include <nlohmann/json.hpp>
#include <optional>
#define tl std
namespace nlohmann {
template<class J, class T>
inline void from_json(const J &j, tl::optional<T> &v)
{
if (j.is_null()) {
v = tl::nullopt;
} else {
v = j.template get<T>();
}
}
template<class J, class T>
inline void to_json(J &j, const tl::optional<T> &o)
{
if (o.has_value()) {
j = o.value();
}
}
} // namespace nlohmann
namespace linglong {
template<class T>
tl::optional<T> optional(const nlohmann::json &j, const char *key)
{
tl::optional<T> o;
auto iter = j.template find(key);
if (iter != j.end()) {
o = iter->template get<tl::optional<T>>();
}
return o;
}
} // namespace linglong
#endif /* LINGLONG_BOX_SRC_UTIL_JSON_H_ */

View File

@ -0,0 +1,42 @@
#include "logger.h"
namespace linglong {
namespace util {
std::string errnoString()
{
return util::format("errno(%d): %s", errno, strerror(errno));
}
std::string RetErrString(int ret)
{
return util::format("ret(%d),errno(%d): %s", ret, errno, strerror(errno));
}
static Logger::Level getLogLevelFromStr(std::string str)
{
if (str == "Debug") {
return Logger::Debug;
} else if (str == "Info") {
return Logger::Info;
} else if (str == "Warning") {
return Logger::Warring;
} else if (str == "Error") {
return Logger::Error;
} else if (str == "Fatal") {
return Logger::Fatal;
} else {
return Logger::Info;
}
}
static Logger::Level initLogLevel()
{
auto env = getenv("LINGLONG_LOG_LEVEL");
return getLogLevelFromStr(env ? env : "");
}
Logger::Level Logger::LOGLEVEL = initLogLevel();
} // namespace util
} // namespace linglong

107
src/modules/util/logger.h Normal file
View File

@ -0,0 +1,107 @@
/*
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef LINGLONG_BOX_SRC_UTIL_LOGGER_H_
#define LINGLONG_BOX_SRC_UTIL_LOGGER_H_
#include "util.h"
#include <unistd.h>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstring>
#include <utility>
namespace linglong {
namespace util {
std::string errnoString();
std::string RetErrString(int);
class Logger
{
public:
enum Level {
Debug,
Info,
Warring,
Error,
Fatal,
};
explicit Logger(Level l, const char *fn, int line)
: level(l)
, function(fn)
, line(line) {};
~Logger()
{
std::string prefix;
if (level < LOGLEVEL) {
return;
}
switch (level) {
case Debug:
prefix = "[DBG |";
std::cout << prefix << getpid() << " | " << function << ":" << line << " ] " << ss.str() << std::endl;
break;
case Info:
prefix = "[IFO |";
std::cout << "\033[1;96m";
std::cout << prefix << getpid() << " | " << function << ":" << line << " ] " << ss.str();
std::cout << "\033[0m" << std::endl;
break;
case Warring:
prefix = "[WAN |";
std::cout << "\033[1;93m";
std::cout << prefix << getpid() << " | " << function << ":" << line << " ] " << ss.str();
std::cout << "\033[0m" << std::endl;
break;
case Error:
prefix = "[ERR |";
std::cout << "\033[1;31m";
std::cout << prefix << getpid() << " | " << function << ":" << line << " ] " << ss.str();
std::cout << "\033[0m" << std::endl;
break;
case Fatal:
prefix = "[FAL |";
std::cout << "\033[1;91m";
std::cout << prefix << getpid() << " | " << function << ":" << line << " ] " << ss.str();
std::cout << "\033[0m" << std::endl;
exit(-1);
break;
}
}
template<class T>
Logger &operator<<(const T &x)
{
ss << x << " ";
return *this;
}
private:
static Level LOGLEVEL;
Level level = Debug;
const char *function;
int line;
std::ostringstream ss;
};
} // namespace util
} // namespace linglong
#define logDbg() (linglong::util::Logger(linglong::util::Logger::Debug, __FUNCTION__, __LINE__))
#define logWan() (linglong::util::Logger(linglong::util::Logger::Warring, __FUNCTION__, __LINE__))
#define logInf() (linglong::util::Logger(linglong::util::Logger::Info, __FUNCTION__, __LINE__))
#define logErr() (linglong::util::Logger(linglong::util::Logger::Error, __FUNCTION__, __LINE__))
#define logFal() (linglong::util::Logger(linglong::util::Logger::Fatal, __FUNCTION__, __LINE__))
#endif /* LINGLONG_BOX_SRC_UTIL_LOGGER_H_ */

19
src/modules/util/macro.h Normal file
View File

@ -0,0 +1,19 @@
/*
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef LINGLONG_BOX_SRC_UTIL_MACRO_H_
#define LINGLONG_BOX_SRC_UTIL_MACRO_H_
#define LINGLONG 118
#define LL_VAL(str) #str
#define LL_TOSTRING(str) LL_VAL(str)
#endif /* LINGLONG_BOX_SRC_UTIL_MACRO_H_ */

View File

@ -0,0 +1,544 @@
/*
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef LINGLONG_BOX_SRC_UTIL_OCI_RUNTIME_H_
#define LINGLONG_BOX_SRC_UTIL_OCI_RUNTIME_H_
#include <sys/mount.h>
#include "util.h"
namespace linglong {
#define LLJS_FROM(KEY) (o.KEY = j.at(#KEY).get<decltype(o.KEY)>())
#define LLJS_FROM_OPT(KEY) (o.KEY = optional<decltype(o.KEY)::value_type>(j, #KEY))
#define LLJS_TO(KEY) (j[#KEY] = o.KEY)
#define LLJS_FROM_OBJ(TYPE) inline void from_json(const nlohmann::json &j, TYPE &o)
#define LLJS_TO_OBJ(TYPE) inline void to_json(nlohmann::json &j, const TYPE &o)
#undef linux
struct Root {
std::string path;
tl::optional<bool> readonly;
};
LLJS_FROM_OBJ(Root)
{
LLJS_FROM(path);
LLJS_FROM_OPT(readonly);
}
LLJS_TO_OBJ(Root)
{
LLJS_TO(path);
LLJS_TO(readonly);
}
struct Process {
util::str_vec args;
util::str_vec env;
std::string cwd;
};
inline void from_json(const nlohmann::json &j, Process &o)
{
o.args = j.at("args").get<util::str_vec>();
o.env = j.at("env").get<util::str_vec>();
o.cwd = j.at("cwd").get<std::string>();
}
inline void to_json(nlohmann::json &j, const Process &o)
{
j["args"] = o.args;
j["env"] = o.env;
j["cwd"] = o.cwd;
}
struct Mount {
enum Type {
Unknown,
Bind,
Proc,
Sysfs,
Devpts,
Mqueue,
Tmpfs,
Cgroup,
Cgroup2,
};
std::string destination;
std::string type;
std::string source;
util::str_vec data;
Type fsType;
uint32_t flags = 0u;
};
inline void from_json(const nlohmann::json &j, Mount &o)
{
static std::map<std::string, Mount::Type> fsTypes = {
{"bind", Mount::Bind}, {"proc", Mount::Proc}, {"devpts", Mount::Devpts}, {"mqueue", Mount::Mqueue},
{"tmpfs", Mount::Tmpfs}, {"sysfs", Mount::Sysfs}, {"cgroup", Mount::Cgroup}, {"cgroup2", Mount::Cgroup2},
};
struct mountFlag {
bool clear;
uint32_t flag;
};
static std::map<std::string, mountFlag> optionFlags = {
{"acl", {false, MS_POSIXACL}},
{"async", {true, MS_SYNCHRONOUS}},
{"atime", {true, MS_NOATIME}},
{"bind", {false, MS_BIND}},
{"defaults", {false, 0}},
{"dev", {true, MS_NODEV}},
{"diratime", {true, MS_NODIRATIME}},
{"dirsync", {false, MS_DIRSYNC}},
{"exec", {true, MS_NOEXEC}},
{"iversion", {false, MS_I_VERSION}},
{"lazytime", {false, MS_LAZYTIME}},
{"loud", {true, MS_SILENT}},
{"mand", {false, MS_MANDLOCK}},
{"noacl", {true, MS_POSIXACL}},
{"noatime", {false, MS_NOATIME}},
{"nodev", {false, MS_NODEV}},
{"nodiratime", {false, MS_NODIRATIME}},
{"noexec", {false, MS_NOEXEC}},
{"noiversion", {true, MS_I_VERSION}},
{"nolazytime", {true, MS_LAZYTIME}},
{"nomand", {true, MS_MANDLOCK}},
{"norelatime", {true, MS_RELATIME}},
{"nostrictatime", {true, MS_STRICTATIME}},
{"nosuid", {false, MS_NOSUID}},
// {"nosymfollow",{false, MS_NOSYMFOLLOW}}, // since kernel 5.10
{"rbind", {false, MS_BIND | MS_REC}},
{"relatime", {false, MS_RELATIME}},
{"remount", {false, MS_REMOUNT}},
{"ro", {false, MS_RDONLY}},
{"rw", {true, MS_RDONLY}},
{"silent", {false, MS_SILENT}},
{"strictatime", {false, MS_STRICTATIME}},
{"suid", {true, MS_NOSUID}},
{"sync", {false, MS_SYNCHRONOUS}},
// {"symfollow",{true, MS_NOSYMFOLLOW}}, // since kernel 5.10
};
o.destination = j.at("destination").get<std::string>();
o.type = j.at("type").get<std::string>();
o.fsType = fsTypes.find(o.type)->second;
if (o.fsType == Mount::Bind) {
o.flags = MS_BIND;
}
o.source = j.at("source").get<std::string>();
o.data = {};
// Parse options to data and flags.
// FIXME: support "propagation flags" and "recursive mount attrs"
// https://github.com/opencontainers/runc/blob/c83abc503de7e8b3017276e92e7510064eee02a8/libcontainer/specconv/spec_linux.go#L958
auto options = j.value("options", util::str_vec());
for (auto const &opt : options) {
auto it = optionFlags.find(opt);
if (it != optionFlags.end()) {
if (it->second.clear) {
o.flags &= ~it->second.flag;
} else
o.flags |= it->second.flag;
} else {
o.data.push_back(opt);
}
}
}
inline void to_json(nlohmann::json &j, const Mount &o)
{
j["destination"] = o.destination;
j["source"] = o.source;
j["type"] = o.type;
j["options"] = o.data; // FIXME: this data is not original options, some of them have been prased to flags.
}
struct Namespace {
int type;
};
static std::map<std::string, int> namespaceType = {
{"pid", CLONE_NEWPID}, {"uts", CLONE_NEWUTS}, {"mount", CLONE_NEWNS}, {"cgroup", CLONE_NEWCGROUP},
{"network", CLONE_NEWNET}, {"ipc", CLONE_NEWIPC}, {"user", CLONE_NEWUSER},
};
inline void from_json(const nlohmann::json &j, Namespace &o)
{
o.type = namespaceType.find(j.at("type").get<std::string>())->second;
}
inline void to_json(nlohmann::json &j, const Namespace &o)
{
auto matchPair = std::find_if(std::begin(namespaceType), std::end(namespaceType),
[&](const std::pair<std::string, int> &pair) { return pair.second == o.type; });
j["type"] = matchPair->first;
}
struct IDMap {
uint64_t containerID = 0u;
uint64_t hostID = 0u;
uint64_t size = 0u;
};
inline void from_json(const nlohmann::json &j, IDMap &o)
{
o.hostID = j.value("hostID", 0);
o.containerID = j.value("containerID", 0);
o.size = j.value("size", 0);
}
inline void to_json(nlohmann::json &j, const IDMap &o)
{
j["hostID"] = o.hostID;
j["containerID"] = o.containerID;
j["size"] = o.size;
}
typedef std::string SeccompAction;
typedef std::string SeccompArch;
struct SyscallArg {
u_int index; // require
u_int64_t value; // require
u_int64_t valueTwo; // optional
std::string op; // require
};
inline void from_json(const nlohmann::json &j, SyscallArg &o)
{
o.index = j.at("index").get<u_int>();
o.value = j.at("value").get<u_int64_t>();
o.valueTwo = j.value("valueTwo", u_int64_t());
o.op = j.at("op").get<std::string>();
}
inline void to_json(nlohmann::json &j, const SyscallArg &o)
{
j["index"] = o.index;
j["value"] = o.value;
j["valueTwo"] = o.valueTwo;
j["op"] = o.op;
}
struct Syscall {
util::str_vec names;
SeccompAction action;
std::vector<SyscallArg> args;
};
inline void from_json(const nlohmann::json &j, Syscall &o)
{
o.names = j.at("names").get<util::str_vec>();
o.action = j.at("action").get<SeccompAction>();
o.args = j.value("args", std::vector<SyscallArg>());
}
inline void to_json(nlohmann::json &j, const Syscall &o)
{
j["names"] = o.names;
j["action"] = o.action;
j["args"] = o.args;
}
struct Seccomp {
SeccompAction defaultAction = "INVALID_ACTION";
std::vector<SeccompArch> architectures;
std::vector<Syscall> syscalls;
};
inline void from_json(const nlohmann::json &j, Seccomp &o)
{
o.defaultAction = j.at("defaultAction").get<std::string>();
o.architectures = j.value("architectures", std::vector<SeccompArch> {});
o.syscalls = j.value("syscalls", std::vector<Syscall> {});
}
inline void to_json(nlohmann::json &j, const Seccomp &o)
{
j["defaultAction"] = o.defaultAction;
j["architectures"] = o.architectures;
j["syscalls"] = o.syscalls;
}
// https://github.com/containers/crun/blob/main/crun.1.md#memory-controller
struct ResourceMemory {
int64_t limit = -1;
int64_t reservation = -1;
int64_t swap = -1;
};
inline void from_json(const nlohmann::json &j, ResourceMemory &o)
{
o.limit = j.value("limit", -1);
o.reservation = j.value("reservation", -1);
o.swap = j.value("swap", -1);
}
inline void to_json(nlohmann::json &j, const ResourceMemory &o)
{
j["limit"] = o.limit;
j["reservation"] = o.reservation;
j["swap"] = o.swap;
}
// https://github.com/containers/crun/blob/main/crun.1.md#cpu-controller
// support v1 and v2 with conversion
struct ResourceCPU {
u_int64_t shares = 1024;
int64_t quota = 100000;
u_int64_t period = 100000;
// int64_t realtimeRuntime;
// int64_t realtimePeriod;
// std::string cpus;
// std::string mems;
};
inline void from_json(const nlohmann::json &j, ResourceCPU &o)
{
o.shares = j.value("shares", 1024);
o.quota = j.value("quota", 100000);
o.period = j.value("period", 100000);
}
inline void to_json(nlohmann::json &j, const ResourceCPU &o)
{
j["shares"] = o.shares;
j["quota"] = o.quota;
j["period"] = o.period;
}
struct Resources {
ResourceMemory memory;
ResourceCPU cpu;
};
inline void from_json(const nlohmann::json &j, Resources &o)
{
o.cpu = j.value("cpu", ResourceCPU());
o.memory = j.value("memory", ResourceMemory());
}
inline void to_json(nlohmann::json &j, const Resources &o)
{
j["cpu"] = o.cpu;
j["memory"] = o.memory;
}
struct Linux {
std::vector<Namespace> namespaces;
std::vector<IDMap> uidMappings;
std::vector<IDMap> gidMappings;
tl::optional<Seccomp> seccomp;
std::string cgroupsPath;
Resources resources;
};
inline void from_json(const nlohmann::json &j, Linux &o)
{
o.namespaces = j.at("namespaces").get<std::vector<Namespace>>();
o.uidMappings = j.value("uidMappings", std::vector<IDMap> {});
o.gidMappings = j.value("gidMappings", std::vector<IDMap> {});
o.seccomp = optional<decltype(o.seccomp)::value_type>(j, "seccomp");
o.cgroupsPath = j.value("cgroupsPath", "");
o.resources = j.value("resources", Resources());
}
inline void to_json(nlohmann::json &j, const Linux &o)
{
j["namespaces"] = o.namespaces;
j["uidMappings"] = o.uidMappings;
j["gidMappings"] = o.gidMappings;
j["seccomp"] = o.seccomp;
j["cgroupsPath"] = o.cgroupsPath;
j["resources"] = o.resources;
}
/*
"hooks": {
"prestart": [
{
"path": "/usr/bin/fix-mounts",
"args": ["fix-mounts", "arg1", "arg2"],
"env": [ "key1=value1"]
},
{
"path": "/usr/bin/setup-network"
}
],
"poststart": [
{
"path": "/usr/bin/notify-start",
"timeout": 5
}
],
"poststop": [
{
"path": "/usr/sbin/cleanup.sh",
"args": ["cleanup.sh", "-f"]
}
]
}
*/
struct Hook {
std::string path;
tl::optional<util::str_vec> args;
tl::optional<std::vector<std::string>> env;
};
inline void from_json(const nlohmann::json &j, Hook &o)
{
LLJS_FROM(path);
LLJS_FROM_OPT(args);
LLJS_FROM_OPT(env);
}
inline void to_json(nlohmann::json &j, const Hook &o)
{
j["path"] = o.path;
j["args"] = o.args;
j["env"] = o.env;
}
struct Hooks {
tl::optional<std::vector<Hook>> prestart;
tl::optional<std::vector<Hook>> poststart;
tl::optional<std::vector<Hook>> poststop;
};
inline void from_json(const nlohmann::json &j, Hooks &o)
{
LLJS_FROM_OPT(prestart);
LLJS_FROM_OPT(poststart);
LLJS_FROM_OPT(poststop);
}
inline void to_json(nlohmann::json &j, const Hooks &o)
{
j["poststop"] = o.poststop;
j["poststart"] = o.poststart;
j["prestart"] = o.prestart;
}
struct AnnotationsOverlayfs {
std::string lower_parent;
std::string upper;
std::string workdir;
std::vector<Mount> mounts;
};
LLJS_FROM_OBJ(AnnotationsOverlayfs)
{
LLJS_FROM(lower_parent);
LLJS_FROM(upper);
LLJS_FROM(workdir);
LLJS_FROM(mounts);
}
LLJS_TO_OBJ(AnnotationsOverlayfs)
{
LLJS_TO(lower_parent);
LLJS_TO(upper);
LLJS_TO(workdir);
LLJS_TO(mounts);
}
struct AnnotationsNativeRootfs {
std::vector<Mount> mounts;
};
LLJS_FROM_OBJ(AnnotationsNativeRootfs)
{
LLJS_FROM(mounts);
}
LLJS_TO_OBJ(AnnotationsNativeRootfs)
{
LLJS_TO(mounts);
}
struct Annotations {
std::string container_root_path;
tl::optional<AnnotationsOverlayfs> overlayfs;
tl::optional<AnnotationsNativeRootfs> native;
};
LLJS_FROM_OBJ(Annotations)
{
LLJS_FROM(container_root_path);
LLJS_FROM_OPT(overlayfs);
LLJS_FROM_OPT(native);
}
LLJS_TO_OBJ(Annotations)
{
LLJS_TO(container_root_path);
LLJS_TO(overlayfs);
LLJS_TO(native);
}
struct Runtime {
std::string version;
Root root;
Process process;
std::string hostname;
Linux linux;
tl::optional<std::vector<Mount>> mounts;
tl::optional<Hooks> hooks;
tl::optional<Annotations> annotations;
};
inline void from_json(const nlohmann::json &j, Runtime &o)
{
o.version = j.at("ociVersion").get<std::string>();
o.hostname = j.at("hostname").get<std::string>();
LLJS_FROM(process);
o.mounts = optional<decltype(o.mounts)::value_type>(j, "mounts");
LLJS_FROM(linux);
// maybe optional
LLJS_FROM(root);
o.hooks = optional<decltype(o.hooks)::value_type>(j, "hooks");
LLJS_FROM_OPT(annotations);
}
inline void to_json(nlohmann::json &j, const Runtime &o)
{
j["ociVersion"] = o.version;
j["hostname"] = o.hostname;
j["process"] = o.process;
j["mounts"] = o.mounts;
j["linux"] = o.linux;
j["root"] = o.root;
j["hooks"] = o.hooks;
LLJS_TO(annotations);
}
inline static Runtime fromFile(const std::string &filepath)
{
return util::json::fromFile(filepath).get<Runtime>();
}
inline static Runtime fromString(const std::string &content)
{
return util::json::fromByteArray(content).get<Runtime>();
}
} // namespace linglong
#endif /* LINGLONG_BOX_SRC_UTIL_OCI_RUNTIME_H_ */

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "platform.h"
#include "logger.h"
#include "debug/debug.h"
#include <sched.h>
#include <cstdlib>
#include <sys/mman.h>
#include <unistd.h>
namespace linglong {
const int kStackSize = (1024 * 1024);
namespace util {
int PlatformClone(int (*callback)(void *), int flags, void *arg, ...)
{
char *stack;
char *stackTop;
stack = reinterpret_cast<char *>(
mmap(nullptr, kStackSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0));
if (stack == MAP_FAILED) {
return EXIT_FAILURE;
}
stackTop = stack + kStackSize;
return clone(callback, stackTop, flags, arg);
}
int Exec(const util::str_vec &args, tl::optional<std::vector<std::string>> env_list)
{
auto targetArgc = args.size();
const char *targetArgv[targetArgc + 1];
for (decltype(targetArgc) i = 0; i < targetArgc; i++) {
targetArgv[i] = args[i].c_str();
}
targetArgv[targetArgc] = nullptr;
auto targetEnvc = env_list.has_value() ? env_list->size() : 0;
const char **targetEnvv = targetEnvc ? new const char *[targetEnvc + 1] : nullptr;
if (targetEnvv) {
for (decltype(targetEnvc) i = 0; i < targetEnvc; i++) {
targetEnvv[i] = env_list.value().at(i).c_str();
}
targetEnvv[targetEnvc] = nullptr;
}
logDbg() << "execve" << targetArgv[0] << " in pid:" << getpid();
int ret = execvpe(targetArgv[0], const_cast<char **>(targetArgv), const_cast<char **>(targetEnvv));
delete[] targetEnvv;
return ret;
}
} // namespace util
} // namespace linglong

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef LINGLONG_BOX_SRC_UTIL_PLATFORM_H_
#define LINGLONG_BOX_SRC_UTIL_PLATFORM_H_
#include "common.h"
#include <optional>
#define tl std
namespace linglong {
namespace util {
int PlatformClone(int (*callback)(void *), int flags, void *arg, ...);
int Exec(const util::str_vec &args, tl::optional<std::vector<std::string>> env_list);
} // namespace util
} // namespace linglong
#endif /* LINGLONG_BOX_SRC_UTIL_PLATFORM_H_ */

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "semaphore.h"
#include <sys/sem.h>
#include "logger.h"
namespace linglong {
union semun {
int val;
struct semid_ds *buf;
ushort *array;
};
struct Semaphore::SemaphorePrivate {
explicit SemaphorePrivate(Semaphore *parent = nullptr)
: q_ptr(parent)
{
(void)q_ptr;
}
struct sembuf sem_lock = {0, -1, SEM_UNDO};
struct sembuf sem_unlock = {0, 1, SEM_UNDO};
int sem_id = -1;
Semaphore *q_ptr;
};
Semaphore::Semaphore(int key)
: dd_ptr(new SemaphorePrivate(this))
{
dd_ptr->sem_id = semget(key, 1, IPC_CREAT | 0666);
if (dd_ptr->sem_id < 0) {
logErr() << "semget failed" << util::RetErrString(dd_ptr->sem_id);
}
}
Semaphore::~Semaphore() = default;
int Semaphore::init()
{
union semun sem_union = {0};
sem_union.val = 0;
logDbg() << "semctl " << dd_ptr->sem_id;
if (semctl(dd_ptr->sem_id, 0, SETVAL, sem_union) == -1) {
logErr() << "semctl failed" << util::RetErrString(-1);
}
return 0;
}
int Semaphore::passeren()
{
return semop(dd_ptr->sem_id, &dd_ptr->sem_lock, 1);
}
int Semaphore::vrijgeven()
{
return semop(dd_ptr->sem_id, &dd_ptr->sem_unlock, 1);
}
} // namespace linglong

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef LINGLONG_BOX_SRC_UTIL_SEMAPHORE_H_
#define LINGLONG_BOX_SRC_UTIL_SEMAPHORE_H_
#include <memory>
namespace linglong {
class Semaphore
{
public:
explicit Semaphore(int key);
~Semaphore();
int init();
//! passeren -1 to value
//! if value < 0, block
//! \return
int passeren();
//! passeren +1 to value
//! if value <= 0, release process in queue
//! \return
int vrijgeven();
private:
struct SemaphorePrivate;
std::unique_ptr<SemaphorePrivate> dd_ptr;
};
} // namespace linglong
#endif /* LINGLONG_BOX_SRC_UTIL_SEMAPHORE_H_ */

44
src/modules/util/util.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2020-2021. Uniontech Software Ltd. All rights reserved.
*
* Author: Iceyer <me@iceyer.net>
*
* Maintainer: Iceyer <me@iceyer.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef LINGLONG_BOX_SRC_UTIL_UTIL_H_
#define LINGLONG_BOX_SRC_UTIL_UTIL_H_
#include "macro.h"
#include "common.h"
#include "logger.h"
#include "semaphore.h"
#include "filesystem.h"
#include "json.h"
#include <fstream>
namespace linglong {
namespace util {
namespace json {
inline nlohmann::json fromByteArray(const std::string &content)
{
return nlohmann::json::parse(content);
}
inline nlohmann::json fromFile(const std::string &filepath)
{
std::ifstream f(filepath);
std::string str((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
auto j = fromByteArray(str);
return j;
}
} // namespace json
} // namespace util
} // namespace linglong
#endif /* LINGLONG_BOX_SRC_UTIL_UTIL_H_ */