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,79 @@
#ifndef A7B4B7B1_0422_4EC9_8441_778273A85F9C
#define A7B4B7B1_0422_4EC9_8441_778273A85F9C
#include "../tools/desktop_deconstruction.hpp"
#include <QString>
namespace modules {
namespace ApplicationHelper {
class Helper {
QString m_file;
public:
Helper(const QString &desktop)
: m_file(desktop)
{
}
inline QString desktop() const { return m_file; }
template <typename T>
T value(const QString &key) const
{
QSettings settings = DesktopDeconstruction(m_file);
settings.beginGroup("Desktop Entry");
return settings.value(key).value<T>();
}
QStringList categories() const
{
QStringList result;
QStringList tmp{ value<QString>("Categories").split(";") };
for (auto t : tmp) {
if (t.isEmpty()) {
continue;
}
result << t;
}
return result;
}
QString icon() const
{
return value<QString>("Icon");
}
QString id() const
{
return m_file.split("/").last().split(".").first();
}
QStringList mimetypes() const
{
QStringList result;
QStringList tmp{ value<QString>("MimeType").split(";") };
for (auto t : tmp) {
if (t.isEmpty()) {
continue;
}
result << t;
}
return result;
}
QString comment(const QString &locale) const
{
return value<QString>(QString("Comment[%1]").arg(locale));
}
QString name(const QString &name) const
{
return value<QString>(QString("Name[%1]").arg(name));
}
};
} // namespace ApplicationHelper
} // namespace modules
#endif /* A7B4B7B1_0422_4EC9_8441_778273A85F9C */

View File

@ -0,0 +1,18 @@
#ifndef BASIC_H_
#define BASIC_H_
#include <nlohmann/json.hpp>
namespace Methods {
struct Basic {
std::string type;
};
using json = nlohmann::json;
inline void from_json(const json &j, Basic &basic) {
j.at("type").get_to(basic.type);
}
} // namespace Methods
#endif // BASIC_H_

View File

@ -0,0 +1,25 @@
#ifndef C664E26D_6517_412B_950F_07E20963349E
#define C664E26D_6517_412B_950F_07E20963349E
#include <nlohmann/json.hpp>
namespace Methods {
struct Instance {
std::string hash;
std::string type{ "instance" };
};
using json = nlohmann::json;
inline void to_json(json &j, const Instance &instance)
{
j = json{ { "type", instance.type }, { "hash", instance.hash } };
}
inline void from_json(const json &j, Instance &instance)
{
j.at("hash").get_to(instance.hash);
}
} // namespace Methods
#endif /* C664E26D_6517_412B_950F_07E20963349E */

View File

@ -0,0 +1,27 @@
#ifndef QUIT_H_
#define QUIT_H_
#include <nlohmann/json.hpp>
namespace Methods {
struct Quit {
std::string date;
std::string type{ "quit" };
std::string id;
int code;
};
using json = nlohmann::json;
inline void to_json(json &j, const Quit &quit)
{
j = json{ { "type", quit.type }, { "date", quit.date }, { "id", quit.id }, { "code", quit.code } };
}
inline void from_json(const json &j, Quit &quit)
{
j.at("id").get_to(quit.id);
j.at("date").get_to(quit.date);
j.at("code").get_to(quit.code);
}
} // namespace Methods
#endif // QUIT_H_

View File

@ -0,0 +1,29 @@
#ifndef REGISTER_H_
#define REGISTER_H_
#include <nlohmann/json.hpp>
namespace Methods {
struct Registe {
std::string date;
std::string id;
std::string type{ "registe" };
std::string hash;
bool state;
};
using json = nlohmann::json;
inline void to_json(json &j, const Registe &registe)
{
j = json{ { "type", registe.type }, { "id", registe.id }, { "hash", registe.hash }, { "state", registe.state }, { "date", registe.date } };
}
inline void from_json(const json &j, Registe &registe)
{
j.at("id").get_to(registe.id);
j.at("date").get_to(registe.date);
j.at("hash").get_to(registe.hash);
j.at("state").get_to(registe.state);
}
} // namespace Methods
#endif // REGISTER_H_

View File

@ -0,0 +1,36 @@
#ifndef B0B88BD6_CF1E_4E87_926A_E6DBE6B9B19C
#define B0B88BD6_CF1E_4E87_926A_E6DBE6B9B19C
#include <map>
#include <nlohmann/json.hpp>
#include <utility>
#include <vector>
namespace Methods {
struct Task {
std::string id;
std::string runId;
std::string type{ "task" };
std::string date;
std::vector<std::string> arguments;
std::multimap<std::string, std::string> environments;
};
using json = nlohmann::json;
inline void to_json(json &j, const Task &task)
{
j = json{ { "type", task.type }, { "id", task.id }, { "run_id", task.runId }, { "date", task.date }, { "arguments", task.arguments }, { "environments", task.environments } };
}
inline void from_json(const json &j, Task &task)
{
j.at("id").get_to(task.id);
j.at("run_id").get_to(task.runId);
j.at("date").get_to(task.date);
j.at("arguments").get_to(task.arguments);
j.at("environments").get_to(task.environments);
}
} // namespace Methods
#endif /* B0B88BD6_CF1E_4E87_926A_E6DBE6B9B19C */

View File

@ -0,0 +1,124 @@
#include "client.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <thread>
namespace Socket {
struct ClientPrivate {
Client* q_ptr;
int socket_fd;
std::function<void(const std::vector<char>&)> readFunc;
std::thread* readThread;
ClientPrivate(Client* client) : q_ptr(client), readThread(nullptr) {}
~ClientPrivate()
{
if (readThread) {
close(socket_fd);
readThread->join();
delete readThread;
}
}
bool connect(const std::string& host)
{
sockaddr_un address;
if ((socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) {
printf("socket() failed\n");
return false;
}
memset(&address, 0, sizeof(struct sockaddr_un));
address.sun_family = AF_LOCAL;
snprintf(address.sun_path, host.size() + 1, "%s", host.c_str());
if (::connect(socket_fd, (struct sockaddr*) &address, sizeof(struct sockaddr_un)) != 0) {
printf("connect() failed\n");
return false;
}
if (readThread) {
return false;
}
if (readFunc) {
readThread = new std::thread([=] {
char buf[512];
std::vector<char> result;
int bytesRead;
while ((bytesRead = recv(socket_fd, buf, 512, 0)) > 0) {
if (bytesRead == -1) {
return;
}
for (int i = 0; i < bytesRead; i++) {
result.push_back(buf[i]);
}
if (buf[bytesRead - 1] == '\0') {
readFunc(result);
result.clear();
}
};
});
readThread->detach();
}
return true;
}
nlohmann::json get(const nlohmann::json& call)
{
send(call);
char buf[512];
std::string result;
int bytesRead;
while ((bytesRead = recv(socket_fd, buf, 512, 0)) > 0) {
for (int i = 0; i < bytesRead; i++) {
result += buf[i];
}
if (buf[bytesRead - 1] == '\0') {
break;
}
};
return nlohmann::json::parse(result);
}
size_t send(const nlohmann::json& call)
{
std::string data = call.dump();
data += '\0';
return write(socket_fd, data.c_str(), data.length());
}
};
Client::Client() : d_ptr(new ClientPrivate(this)) {}
Client::~Client() {}
bool Client::connect(const std::string& host)
{
return d_ptr->connect(host);
}
nlohmann::json Client::get(const nlohmann::json& call)
{
return d_ptr->get(call);
}
size_t Client::send(const nlohmann::json& call)
{
return d_ptr->send(call);
}
void Client::onReadyRead(std::function<void(const std::vector<char>&)> func)
{
d_ptr->readFunc = func;
}
void Client::waitForFinished()
{
d_ptr->readThread->join();
}
} // namespace Socket

View File

@ -0,0 +1,25 @@
#ifndef B1D5EB4F_7645_4BDA_87D6_6B80A4910014
#define B1D5EB4F_7645_4BDA_87D6_6B80A4910014
#include <functional>
#include <memory>
#include <nlohmann/json.hpp>
#include <string>
namespace Socket {
class ClientPrivate;
class Client {
std::unique_ptr<ClientPrivate> d_ptr;
public:
Client();
~Client();
bool connect(const std::string& host);
nlohmann::json get(const nlohmann::json& call);
size_t send(const nlohmann::json& call);
void onReadyRead(std::function<void(const std::vector<char>&)> func);
void waitForFinished();
};
} // namespace Socket
#endif /* B1D5EB4F_7645_4BDA_87D6_6B80A4910014 */

View File

@ -0,0 +1,147 @@
#include "server.h"
#include <qnamespace.h>
#include <qobject.h>
#include <qobjectdefs.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <QThread>
#include <QtConcurrent/QtConcurrent>
#include <iostream>
namespace Socket {
class ServerPrivate : public QObject {
Q_OBJECT
public:
Server *q_ptr;
int socket_fd;
QThread *workThread;
Q_SIGNALS:
void requestStart();
public:
ServerPrivate(Server *server) : QObject(), q_ptr(server), socket_fd(-1)
{
if ((socket_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
std::cout << "socket() failed" << std::endl;
return;
}
connect(this, &ServerPrivate::requestStart, this, &ServerPrivate::work, Qt::QueuedConnection);
}
~ServerPrivate() {}
void work()
{
// start a thread to listen client read
while (true) {
int socket = accept(socket_fd, nullptr, nullptr);
if (socket == -1) {
std::cout << "accept() failed" << std::endl;
return;
}
QtConcurrent::run([=] {
int readBytes = 0;
char buffer[1024];
std::vector<char> data;
while (true) {
readBytes = recv(socket, buffer, 1024, 0);
if (readBytes == -1) {
std::cout << "client connect closed" << std::endl;
break;
}
if (readBytes == 0) {
break;
}
for (int i = 0; i != readBytes; i++) {
data.push_back(buffer[i]);
}
if (buffer[readBytes - 1] == '\0') {
emit q_ptr->onReadyRead(socket, data);
data.clear();
}
}
});
}
}
bool listen(const std::string &host)
{
if (socket_fd < 0) {
return false;
}
struct sockaddr_un addr;
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
snprintf(addr.sun_path, host.size() + 1, "%s", host.c_str());
if (remove(host.c_str()) == -1 && errno != ENOENT) {
std::cout << "remove() failed" << std::endl;
return false;
}
if (bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
std::cout << "bind() failed" << std::endl;
return false;
}
if (::listen(socket_fd, sizeof(uint)) < 0) {
std::cout << "listen() failed" << std::endl;
return false;
}
return true;
}
void write(int socket, const std::vector<char> &data)
{
::write(socket, data.data(), data.size());
}
void closeClient(int socket)
{
::close(socket);
}
};
Server::Server() : QObject(nullptr), d_ptr(new ServerPrivate(this))
{
qRegisterMetaType<std::vector<char>>("VectorChar");
}
Server::~Server() {}
bool Server::listen(const std::string &host)
{
if (d_ptr->workThread) {
return false;
}
const bool result = d_ptr->listen(host);
if (!result) {
return result;
}
d_ptr->workThread = new QThread;
d_ptr->moveToThread(d_ptr->workThread);
d_ptr->workThread->start();
emit d_ptr->requestStart();
return result;
}
void Server::write(int socket, const std::vector<char> &data)
{
d_ptr->write(socket, data);
}
void Server::close(int socket)
{
d_ptr->closeClient(socket);
}
} // namespace Socket
#include "server.moc"

View File

@ -0,0 +1,27 @@
#ifndef F358257E_94E5_4A6C_91A8_4B6E57999E7B
#define F358257E_94E5_4A6C_91A8_4B6E57999E7B
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include <QObject>
namespace Socket {
class ServerPrivate;
class Server : public QObject {
Q_OBJECT
std::unique_ptr<ServerPrivate> d_ptr;
public:
Server();
~Server();
bool listen(const std::string& host);
void write(int socket, const std::vector<char>& data);
void close(int socket);
Q_SIGNALS:
void onReadyRead(int socket, const std::vector<char>& data) const;
};
} // namespace Socket
#endif /* F358257E_94E5_4A6C_91A8_4B6E57999E7B */

View File

@ -0,0 +1,157 @@
#ifndef BB9B5BB3_BEAF_4D25_B4F6_55273B263973
#define BB9B5BB3_BEAF_4D25_B4F6_55273B263973
#ifdef USE_QT
#include <QSettings>
#include <QTextStream>
static QSettings DesktopDeconstruction(const QString &desktop)
{
auto IniReadFunc = [](QIODevice &device, QSettings::SettingsMap &settingsMap) -> bool {
QTextStream stream(&device);
QString group;
while (!stream.atEnd()) {
QString line = stream.readLine();
if (group.isEmpty()) {
if (line.front() == '[' && line.back() == ']') {
group = line.mid(1, line.size() - 2);
}
}
else {
if (line.isEmpty()) {
group.clear();
}
else {
int index = line.indexOf("=");
if (index != -1) {
QString name = group + "/" + line.mid(0, index);
QVariant value = QVariant(line.mid(index + 1));
settingsMap.insert(name, value);
}
}
}
}
return true;
};
return QSettings(desktop, QSettings::registerFormat("ini", IniReadFunc, nullptr));
}
#else
#include <algorithm>
#include <any>
#include <fstream>
#include <iostream>
#include <memory>
#include <regex>
#include <string>
#include <utility>
#include <variant>
#include <vector>
class DesktopDeconstruction
{
std::string m_path;
std::string m_group;
struct Entry {
typedef std::string Key;
typedef std::any Value;
std::string name;
std::vector<std::pair<Key, Value>> pairs;
};
std::vector<std::shared_ptr<Entry>> _parse()
{
std::ifstream file(m_path);
if (!file) {
return {};
}
std::string line;
std::regex group_regex("\\[(.*?)\\]");
std::vector<std::shared_ptr<struct Entry>> entrys;
std::shared_ptr<Entry> currentEntry;
while (std::getline(file, line)) {
// 匹配 group如果是就进入判断
if (std::regex_match(line, group_regex)) {
std::smatch result;
if (std::regex_search(line, result, group_regex)) {
currentEntry = std::make_shared<Entry>();
currentEntry.get()->name = result.str();
entrys.push_back(currentEntry);
}
continue;
}
if (!currentEntry) {
continue;
}
// 跳过 # 开头的注释
if (!line.empty() && line[0] == '#') {
continue;
}
const size_t index = line.find('=');
const std::string key = line.substr(0, index);
const std::any value = line.substr(index + 1, line.size());
currentEntry.get()->pairs.push_back({key, value});
}
file.close();
return entrys;
}
public:
DesktopDeconstruction(const std::string &path)
: m_path(path)
{
}
~DesktopDeconstruction()
{
}
void beginGroup(const std::string group)
{
m_group = group;
}
void endGroup()
{
m_group.clear();
}
std::vector<std::string> listKeys()
{
std::vector<std::shared_ptr<Entry>> entrys{ _parse() };
std::vector<std::string> result;
for (const std::shared_ptr<Entry> entry : entrys) {
for (const auto pair : entry.get()->pairs) {
result.push_back(pair.first);
}
}
return result;
}
template <typename T>
T value(const std::string key)
{
std::vector<std::shared_ptr<Entry>> entrys{ _parse() };
for (const std::shared_ptr<Entry> entry : entrys) {
if (entry.get()->name == "[" + m_group + "]") {
for (const auto pair : entry.get()->pairs) {
if (pair.first == key) {
return std::any_cast<T>(pair.second);
}
}
}
}
return {};
}
};
#endif
#endif /* BB9B5BB3_BEAF_4D25_B4F6_55273B263973 */

11
src/modules/tools/query.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef QUERY_H
#define QUERY_H
#include <QStringList>
namespace Tools {
}
#endif // QUERY_H

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_ */