Skip to content

Commit

Permalink
fix: bring enter back
Browse files Browse the repository at this point in the history
Signed-off-by: black-desk <[email protected]>
  • Loading branch information
l631197874 authored and black-desk committed Jan 22, 2024
1 parent d74abc1 commit ec78c8f
Showing 1 changed file with 96 additions and 115 deletions.
211 changes: 96 additions & 115 deletions src/linglong/cli/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ A CLI program to run application and manage linglong pagoda and tiers.
ll-cli [--json] --version
ll-cli [--json] run APP [--no-dbus-proxy] [--dbus-proxy-cfg=PATH] [--] [COMMAND...]
ll-cli [--json] ps
ll-cli [--json] exec (APP | PAGODA) [--working-directory=PATH] [--] COMMAND...
ll-cli [--json] enter (APP | PAGODA) [--working-directory=PATH] [--] [COMMAND...]
ll-cli [--json] kill (APP | PAGODA)
ll-cli [--json] exec PAGODA [--working-directory=PATH] [--] COMMAND...
ll-cli [--json] enter PAGODA [--working-directory=PATH] [--] [COMMAND...]
ll-cli [--json] kill PAGODA
ll-cli [--json] [--no-dbus] install TIER...
ll-cli [--json] uninstall TIER... [--all] [--prune]
ll-cli [--json] upgrade TIER...
Expand Down Expand Up @@ -189,107 +189,79 @@ int execArgs(const std::vector<std::string> &args, const std::vector<std::string
return execve(command[0], &command[0], &env[0]);
}

int namespaceEnter(pid_t pid, const QStringList &args)
int getChildBoxPID(pid_t pid)
{
int ret;
struct stat fileStat = {};

auto children = childrenOf(pid);
if (children.isEmpty()) {
qDebug() << "get children of pid failed" << errno << strerror(errno);
return -1;
}

pid = childrenOf(pid).value(0);
auto prefix = QString("/proc/%1/ns/").arg(pid);
auto root = QString("/proc/%1/root").arg(pid);
auto proc = QString("/proc/%1").arg(pid);

ret = lstat(proc.toStdString().c_str(), &fileStat);
if (ret < 0) {
qDebug() << "lstat failed" << root << ret << errno << strerror(errno);
return -1;
return 0;
}

QStringList nameSpaceList = {
"mnt", "ipc", "uts", "pid", "net",
// "user",
// TODO: is hard to set user namespace, need carefully fork and unshare
};

QList<int> fds;
for (auto const &nameSpace : nameSpaceList) {
auto currentNameSpace = (prefix + nameSpace).toStdString();
int fd = open(currentNameSpace.c_str(), O_RDONLY);
if (fd < 0) {
qCritical() << "open failed" << currentNameSpace.c_str() << fd << errno
<< strerror(errno);
for (const auto &child : children) {
auto exe = QFile(QString("/proc/%1/exe").arg(child)).symLinkTarget();
if (exe != "/usr/bin/ll-box") {
continue;
}
qDebug() << "push" << fd << currentNameSpace.c_str();
fds.push_back(fd);
return child;
}

int rootFd = open(root.toStdString().c_str(), O_RDONLY);

ret = unshare(CLONE_NEWNS);
if (ret < 0) {
qCritical() << "unshare failed" << ret << errno << strerror(errno);
}
return 0;
}

for (auto fd : fds) {
ret = setns(fd, 0);
if (ret < 0) {
qCritical() << "setns failed" << fd << ret << errno << strerror(errno);
}
close(fd);
}
int namespaceEnter(pid_t pid, const QString &id)
{
int ret;

Check warning on line 212 in src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Unused variable: ret
struct stat fileStat = {};

Check warning on line 213 in src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Variable 'fileStat' is assigned a value that is never used.

ret = fchdir(rootFd);
if (ret < 0) {
qCritical() << "chdir failed" << root << ret << errno << strerror(errno);
auto childBox = getChildBoxPID(pid);
if (childBox == 0) {
qDebug() << "no ll-box process found in child of" << pid;
return -1;
}

ret = chroot(".");
if (ret < 0) {
qCritical() << "chroot failed" << root << ret << errno << strerror(errno);
childBox = getChildBoxPID(childBox);
if (childBox == 0) {
qDebug() << "no ll-box process found in child of" << pid;
return -1;
}

bringDownPermissionsTo(fileStat);

int child = fork();
if (child < 0) {
qCritical() << "fork failed" << child << errno << strerror(errno);
return -1;
}
auto target = QString::number(childBox).toUtf8();

if (0 == child) {
QFile envFile("/run/app/env");
if (!envFile.open(QIODevice::ReadOnly)) {
qCritical() << "open failed" << envFile.fileName() << errno << strerror(errno);
}
auto sysenv = QProcessEnvironment::systemEnvironment();

std::vector<std::string> envVec;
for (const auto &env : envFile.readAll().split('\n')) {
if (!env.isEmpty()) {
envVec.push_back(env.toStdString());
}
QFile envFile(QString("/run/user/%1/linglong/%2/env").arg(getuid()).arg(id));
envFile.open(QIODevice::ReadOnly);
if (envFile.isOpen()) {
QTextStream in(&envFile);
while (!in.atEnd()) {
QString line = in.readLine();
auto name = line.left(line.indexOf('='));
auto value = line.mid(line.indexOf('=') + 1);
sysenv.insert(name, value);
}

std::vector<std::string> argVec(args.size());
std::transform(args.begin(),
args.end(),
argVec.begin(),
[](const QString &str) -> std::string {
return str.toStdString();
});

return execArgs(argVec, envVec);
}

return waitpid(-1, nullptr, 0);
envFile.close();
} else {
qWarning() << "Failed to open env file, not init environment variables.";
}

auto nsenter = QProcess();
nsenter.setProcessEnvironment(sysenv);
nsenter.setInputChannelMode(QProcess::ForwardedInputChannel);
nsenter.setProcessChannelMode(QProcess::ForwardedChannels);
nsenter.setProgram("nsenter");
nsenter.setArguments({ "-t",
target,
"-U",
"-m",
"-p",
"--preserve-credentials",
"--",
"env",
R"(debian_chroot=LINGLONG)",
"bash" });

nsenter.start();
nsenter.waitForFinished(-1);

return nsenter.exitCode();
}

} // namespace
Expand Down Expand Up @@ -364,13 +336,7 @@ int Cli::run(std::map<std::string, docopt::value> &args)
int Cli::exec(std::map<std::string, docopt::value> &args)
{
QString containerId;
if (args["PAGODA"].isString()) {
containerId = QString::fromStdString(args["PAGODA"].asString());
}

if (args["APP"].isString()) {
containerId = QString::fromStdString(args["APP"].asString());
}
containerId = QString::fromStdString(args["PAGODA"].asString());

if (containerId.isEmpty()) {
this->printer.printErr(LINGLONG_ERR(-1, "failed to get container id").value());
Expand Down Expand Up @@ -398,42 +364,62 @@ int Cli::exec(std::map<std::string, docopt::value> &args)

int Cli::enter(std::map<std::string, docopt::value> &args)
{
this->printer.printErr(
LINGLONG_ERR(-1, "Command `enter` has not been implemented yet.").value());
return -1;
QString containerId;

// TODO
containerId = QString::fromStdString(args["PAGODA"].asString());

QString containerId;
if (args["PAGODA"].isString()) {
containerId = QString::fromStdString(args["PAGODA"].asString());
if (args["--working-directory"].isBool() && args["--working-directory"].asBool()) {
qWarning() << "--working-directory is not supported yet";
}

if (args["APP"].isString()) {
containerId = QString::fromStdString(args["APP"].asString());
if (args["COMMAND"].isStringList() && !args["COMMAND"].asStringList().empty()) {
qWarning() << "COMMAND is not supported yet";
}

if (containerId.isEmpty()) {
this->printer.printErr(LINGLONG_ERR(-1, "failed to get container id").value());
return -1;
}

QString cmd;
if (args["COMMAND"].isString()) {
cmd = QString::fromStdString(args["COMMAND"].asString());
if (cmd.isEmpty()) {
this->printer.printErr(LINGLONG_ERR(-1, "failed to get command list").value());
return -1;
auto result = this->appMan.ListContainer().value().result;

QList<QSharedPointer<Container>> containerList;

Check warning on line 386 in src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Unused variable: containerList
const auto doc = QJsonDocument::fromJson(result.toUtf8(), nullptr);
if (!doc.isArray()) {
this->printer.printErr(
LINGLONG_ERR(-1, "container list get from server is not a list").value());
return -1;
}

pid_t pid = 0;
QString id = "";

for (const auto item : doc.array()) {
const auto str = QString(QJsonDocument(item.toObject()).toJson());
QSharedPointer<Container> container(linglong::util::loadJsonString<Container>(str));
if (container->id == containerId) {
pid = container->pid;
id = container->id;
break;
}
if (container->packageName.contains(containerId)) {
pid = container->pid;
id = container->id;
break;
}
}

const auto pid = containerId.toInt();
if (pid == 0) {
this->printer.printErr(LINGLONG_ERR(-1, "no such container").value());
return -1;
}

int reply = namespaceEnter(pid, QStringList{ cmd });
int reply = namespaceEnter(pid, id);
if (reply == -1) {
this->printer.printErr(LINGLONG_ERR(-1, "failed to enter namespace").value());
return -1;
}

return 0;
}

Expand Down Expand Up @@ -461,13 +447,8 @@ int Cli::ps(std::map<std::string, docopt::value> &args)
int Cli::kill(std::map<std::string, docopt::value> &args)
{
QString containerId;
if (args["PAGODA"].isString()) {
containerId = QString::fromStdString(args["PAGODA"].asString());
}

if (args["APP"].isString()) {
containerId = QString::fromStdString(args["APP"].asString());
}
containerId = QString::fromStdString(args["PAGODA"].asString());

if (containerId.isEmpty()) {
this->printer.printErr(LINGLONG_ERR(-1, "failed to get container id").value());
Expand Down

0 comments on commit ec78c8f

Please sign in to comment.