Files
ascend-docker-runtime/cli/src/main.c
2020-07-25 10:45:18 +08:00

252 lines
5.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
* Description: ascend-docker-cli工具配置容器挂载Ascend NPU设备
*/
#define _GNU_SOURCE
#include <stdbool.h>
#include <getopt.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sched.h>
#include <stdlib.h>
#include <unistd.h>
#include "securec.h"
#include "basic.h"
#include "ns.h"
#include "mount.h"
#include "cgrp.h"
#include "logging.h"
#include "options.h"
#define DECIMAL 10
struct ParsedConfig {
char containerNsPath[BUF_SIZE];
char cgroupPath[BUF_SIZE];
int originNsFd;
};
static struct option g_cmdOpts[] = {
{"devices", required_argument, 0, 'd'},
{"pid", required_argument, 0, 'p'},
{"rootfs", required_argument, 0, 'r'},
{"options", required_argument, 0, 'o'},
{0, 0, 0, 0}
};
typedef bool (*CmdArgParser)(struct CmdArgs *args, const char *arg);
static bool DevicesCmdArgParser(struct CmdArgs *args, const char *arg)
{
errno_t err = strcpy_s(args->devices, BUF_SIZE, arg);
if (err != EOK) {
LogError("error: failed to get devices from cmd args.");
return false;
}
return true;
}
static bool PidCmdArgParser(struct CmdArgs *args, const char *arg)
{
errno = 0;
args->pid = strtol(optarg, NULL, DECIMAL);
if (errno != 0) {
LogError("error: failed to convert pid string from cmd args, pid string: %s.", arg);
return false;
}
if (args->pid <= 0) {
LogError("error: invalid pid %d.", args->pid);
return false;
}
return true;
}
static bool RootfsCmdArgParser(struct CmdArgs *args, const char *arg)
{
errno_t err = strcpy_s(args->rootfs, BUF_SIZE, arg);
if (err != EOK) {
LogError("error: failed to get rootfs path from cmd args");
return false;
}
return true;
}
static bool OptionsCmdArgParser(struct CmdArgs *args, const char *arg)
{
errno_t err = strcpy_s(args->options, BUF_SIZE, arg);
if (err != EOK) {
LogError("error: failed to get options string from cmd args");
return false;
}
return true;
}
#define NUM_OF_CMD_ARGS 4
static struct {
const int c;
CmdArgParser parser;
} g_cmdArgParsers[NUM_OF_CMD_ARGS] = {
{'d', DevicesCmdArgParser},
{'p', PidCmdArgParser},
{'r', RootfsCmdArgParser},
{'o', OptionsCmdArgParser}
};
static int ParseOneCmdArg(struct CmdArgs *args, int indicator, const char *value)
{
int i;
for (i = 0; i < NUM_OF_CMD_ARGS; i++) {
if (g_cmdArgParsers[i].c == indicator) {
break;
}
}
if (i == NUM_OF_CMD_ARGS) {
LogError("error: unrecognized cmd arg: indicate char: %c, value: %s.", indicator, value);
return -1;
}
bool isOK = g_cmdArgParsers[i].parser(args, value);
if (!isOK) {
LogError("error: failed while parsing cmd arg, indicate char: %c, value: %s.", indicator, value);
return -1;
}
return 0;
}
static inline bool IsCmdArgsValid(struct CmdArgs *args)
{
return (strlen(args->devices) > 0) && (strlen(args->rootfs) > 0) && (args->pid > 0);
}
int DoPrepare(const struct CmdArgs *args, struct ParsedConfig *config)
{
int ret;
ret = GetNsPath(args->pid, "mnt", config->containerNsPath, BUF_SIZE);
if (ret < 0) {
LogError("error: failed to get container mnt ns path: pid(%d).", args->pid);
return -1;
}
ret = GetCgroupPath(args, config->cgroupPath, BUF_SIZE);
if (ret < 0) {
LogError("error: failed to get cgroup path.");
return -1;
}
char originNsPath[BUF_SIZE] = {0};
ret = GetSelfNsPath("mnt", originNsPath, BUF_SIZE);
if (ret < 0) {
LogError("error: failed to get self ns path.");
return -1;
}
config->originNsFd = open((const char *)originNsPath, O_RDONLY); // proc接口非外部输入
if (config->originNsFd < 0) {
LogError("error: failed to get self ns fd: %s.", originNsPath);
return -1;
}
ret = ParseRuntimeOptions(args->options);
if (ret < 0) {
LogError("error: failed to parse runtime options.");
return -1;
}
return 0;
}
int SetupContainer(struct CmdArgs *args)
{
int ret;
struct ParsedConfig config;
ret = DoPrepare(args, &config);
if (ret < 0) {
LogError("error: failed to prepare nesessary config.");
return -1;
}
// enter container's mount namespace
ret = EnterNsByPath((const char *)config.containerNsPath, CLONE_NEWNS);
if (ret < 0) {
LogError("error: failed to set to container ns: %s.", config.containerNsPath);
close(config.originNsFd);
return -1;
}
ret = DoMounting(args);
if (ret < 0) {
LogError("error: failed to do mounting.");
close(config.originNsFd);
return -1;
}
ret = SetupCgroup(args, (const char *)config.cgroupPath);
if (ret < 0) {
LogError("error: failed to set up cgroup.");
close(config.originNsFd);
return -1;
}
// back to original namespace
ret = EnterNsByFd(config.originNsFd, CLONE_NEWNS);
if (ret < 0) {
LogError("error: failed to set ns back.");
close(config.originNsFd);
return -1;
}
close(config.originNsFd);
return 0;
}
int Process(int argc, char **argv)
{
int c;
int ret;
int optionIndex;
struct CmdArgs args = {0};
while ((c = getopt_long(argc, argv, "d:p:r:o", g_cmdOpts, &optionIndex)) != -1) {
ret = ParseOneCmdArg(&args, c, optarg);
if (ret < 0) {
LogError("error: failed to parse cmd args.");
return -1;
}
}
if (!IsCmdArgsValid(&args)) {
LogError("error: information not completed or valid.");
return -1;
}
ret = SetupContainer(&args);
if (ret < 0) {
return ret;
}
return 0;
}
#ifdef gtest
int _main(int argc, char **argv)
{
#else
int main(int argc, char **argv)
{
#endif
int ret = Process(argc, argv);
return ret;
}