iSulad/src/cmd/lcrc/commands.c

433 lines
12 KiB
C
Raw Normal View History

2019-09-30 10:53:41 -04:00
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. All rights reserved.
* iSulad licensed under the Mulan PSL v1.
* You can use this software according to the terms and conditions of the Mulan PSL v1.
* You may obtain a copy of Mulan PSL v1 at:
* http://license.coscl.org.cn/MulanPSL
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v1 for more details.
* Author: lifeng
* Create: 2017-11-22
* Description: provide container command functions
******************************************************************************/
#include "commands.h"
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <pthread.h>
#include <syslog.h>
#include "arguments.h"
#include "config.h"
#include "log.h"
#include "utils.h"
#include "console.h"
#include "constants.h"
static void send_msg_to_syslog(int argc, const char **argv)
{
int nret = 0;
int fd = -1;
int i = 0;
bool found = false;
ssize_t len = 0;
pid_t ppid = -1;
char cmdline_path[PATH_MAX] = { 0 };
char cmdline[MAX_BUFFER_SIZE + 1] = { 0 };
char *msg = NULL;
const char *target_command[] = { "kill", "restart", "rm", "stop", NULL };
if (argc < 2) {
COMMAND_ERROR("Invalid arguments to send syslog");
return;
}
for (; target_command[i] != NULL; i++) {
if (strcmp(argv[1], target_command[i]) == 0) {
found = true;
}
}
if (!found) {
return;
}
ppid = getppid();
// get parent cmdline, "/proc/ppid/cmdline"
nret = snprintf(cmdline_path, PATH_MAX, "/proc/%d/cmdline", ppid);
if (nret < 0 || nret >= PATH_MAX) {
2019-09-30 10:53:41 -04:00
COMMAND_ERROR("Get parent '%d' cmdline path failed", ppid);
return;
}
fd = util_open(cmdline_path, O_RDONLY, DEFAULT_SECURE_FILE_MODE);
if (fd < 0) {
COMMAND_ERROR("Open parent '%d' cmdline path failed", ppid);
return;
}
len = util_read_nointr(fd, cmdline, MAX_BUFFER_SIZE);
if (len < 0) {
COMMAND_ERROR("Read cmdline failed");
goto free_out;
}
msg = util_string_join(" ", argv, (size_t)argc);
if (msg == NULL) {
msg = util_strdup_s(argv[1]);
}
openlog("isulad-client", LOG_PID, LOG_USER);
syslog(LOG_DEBUG, "received command [%s] from parent [%d] cmdline [%s]", msg, ppid, cmdline);
closelog();
free_out:
close(fd);
free(msg);
}
static void print_version()
{
printf("Version %s, commit %s\n", VERSION, LCRD_GIT_COMMIT);
}
/* compare commands */
int compare_commands(const void *s1, const void *s2)
{
return strcmp((*(const struct command *)s1).name, (*(const struct command *)s2).name);
}
const struct command *command_by_name(const struct command *cmds, const char * const name)
{
size_t i = 0;
if (cmds == NULL) {
return NULL;
}
while (1) {
if (cmds[i].name == NULL) {
return NULL;
}
if (strcmp(cmds[i].name, name) == 0) {
return cmds + i;
}
++i;
}
}
// Default help command if implementation doesn't provide one
int command_default_help(const char * const program_name, struct command *commands, int argc, const char **argv)
{
const struct command *command = NULL;
if (commands == NULL) {
return 1;
}
if (argc == 0) {
size_t i = 0;
size_t max_size = 0;
printf("USAGE:\n");
printf("\t%s <command> [args...]\n", program_name);
printf("\n");
printf("COMMANDS:\n");
for (i = 0; commands[i].name != NULL; i++) {
size_t cmd_size = strlen(commands[i].name);
if (cmd_size > max_size) {
max_size = cmd_size;
}
}
qsort(commands, i, sizeof(commands[0]), compare_commands);
for (i = 0; commands[i].name != NULL; i++) {
printf("\t%*s\t%s\n", -(int)max_size, commands[i].name, commands[i].description);
}
printf("\n");
print_common_help();
return 0;
} else if (argc > 1) {
printf("%s: unrecognized argument: \"%s\"\n", program_name, argv[1]);
return 1;
}
command = command_by_name(commands, argv[0]);
if (command == NULL) {
printf("%s: sub-command \"%s\" not found\n", program_name, argv[0]);
printf("run `lcrc --help` for a list of sub-commands\n");
return 1;
}
if (command->longdesc != NULL) {
printf("%s\n", command->longdesc);
}
return 0;
}
/* run command */
int run_command(struct command *commands, int argc, const char **argv)
{
const struct command *command = NULL;
if (argc == 1) {
return command_default_help(argv[0], commands, argc - 1, (const char **)(argv + 1));
}
2019-11-06 19:33:20 +08:00
if (strcmp(argv[1], "--help") == 0) {
// lcrc help command format: lcrc --help args
2019-09-30 10:53:41 -04:00
return command_default_help(argv[0], commands, argc - 2, (const char **)(argv + 2));
}
if (strcmp(argv[1], "--version") == 0) {
print_version();
return 0;
}
command = command_by_name(commands, argv[1]);
if (command != NULL) {
send_msg_to_syslog(argc, argv);
return command->executor(argc, (const char **)argv);
}
printf("%s: command \"%s\" not found\n", argv[0], argv[1]);
2019-11-06 19:33:20 +08:00
printf("run `%s --help` for a list of sub-commands\n", argv[0]);
2019-09-30 10:53:41 -04:00
return 1;
}
/* free command fifo names */
void free_command_fifo_config(struct command_fifo_config *fifos)
{
if (fifos != NULL) {
if (fifos->stdin_path != NULL) {
free(fifos->stdin_path);
fifos->stdin_path = NULL;
}
if (fifos->stdout_path != NULL) {
free(fifos->stdout_path);
fifos->stdout_path = NULL;
}
if (fifos->stderr_path != NULL) {
free(fifos->stderr_path);
fifos->stderr_path = NULL;
}
if (fifos->stdin_name != NULL) {
free(fifos->stdin_name);
fifos->stdin_name = NULL;
}
if (fifos->stdout_name != NULL) {
free(fifos->stdout_name);
fifos->stdout_name = NULL;
}
if (fifos->stderr_name != NULL) {
free(fifos->stderr_name);
fifos->stderr_name = NULL;
}
free(fifos);
}
}
/* delete command fifo */
void delete_command_fifo(struct command_fifo_config *fifos)
{
int ret;
if (fifos == NULL) {
return;
}
ret = console_fifo_delete(fifos->stdin_name);
if (ret) {
WARN("Delete fifo failed: %s", fifos->stdin_name);
}
ret = console_fifo_delete(fifos->stdout_name);
if (ret) {
WARN("Delete fifo failed: %s", fifos->stdout_name);
}
ret = console_fifo_delete(fifos->stderr_name);
if (ret) {
WARN("Delete fifo failed: %s", fifos->stderr_name);
}
ret = util_recursive_rmdir(fifos->stdin_path, 0);
if (ret) {
WARN("Remove directory failed: %s", fifos->stdin_path);
}
ret = util_recursive_rmdir(fifos->stdout_path, 0);
if (ret) {
WARN("Remove directory failed: %s", fifos->stdout_path);
}
ret = util_recursive_rmdir(fifos->stderr_path, 0);
if (ret) {
WARN("Remove directory failed: %s", fifos->stderr_path);
}
free_command_fifo_config(fifos);
}
static int do_create_console_fifo(const char *subpath, const char *stdflag, char **out_fifo_dir, char **out_fifo_name)
{
int ret = 0;
char fifo_dir[PATH_MAX] = { 0 };
char fifo_name[PATH_MAX] = { 0 };
ret = console_fifo_name(CLIENT_RUNDIR, subpath, stdflag, fifo_name, sizeof(fifo_name), fifo_dir,
sizeof(fifo_dir), true);
if (ret != 0) {
ERROR("Failed to get console fifo name.");
ret = -1;
goto out;
}
if (console_fifo_create(fifo_name)) {
ERROR("Failed to create console fifo.");
ret = -1;
goto out;
}
*out_fifo_dir = util_strdup_s(fifo_dir);
*out_fifo_name = util_strdup_s(fifo_name);
out:
return ret;
}
int create_console_fifos(bool attach_stdin, bool attach_stdout, bool attach_stderr, const char *name, const char *type,
struct command_fifo_config **pconsole_fifos)
{
int ret = 0;
char subpath[PATH_MAX] = { 0 };
struct command_fifo_config *fifos = NULL;
fifos = util_common_calloc_s(sizeof(struct command_fifo_config));
if (fifos == NULL) {
ERROR("Failed to malloc memory for FIFO names.");
return -1;
}
ret = snprintf(subpath, sizeof(subpath), "%s/%s-%u-%u", name, type, (unsigned int)getpid(),
(unsigned int)pthread_self());
if (ret < 0 || (size_t)ret >= sizeof(subpath)) {
2019-09-30 10:53:41 -04:00
ERROR("Path is too long");
goto cleanup;
}
if (attach_stdin) {
ret = do_create_console_fifo(subpath, "in", &fifos->stdin_path, &fifos->stdin_name);
if (ret != 0) {
goto cleanup;
}
INFO("FIFO:%s create for start success.", fifos->stdin_name);
}
if (attach_stdout) {
ret = do_create_console_fifo(subpath, "out", &fifos->stdout_path, &fifos->stdout_name);
if (ret != 0) {
goto cleanup;
}
INFO("FIFO:%s create for start success.", fifos->stdout_name);
}
if (attach_stderr) {
ret = do_create_console_fifo(subpath, "err", &fifos->stderr_path, &fifos->stderr_name);
if (ret != 0) {
goto cleanup;
}
INFO("FIFO:%s create for start success.", fifos->stderr_name);
}
*pconsole_fifos = fifos;
return 0;
cleanup:
console_fifo_delete(fifos->stdin_name);
console_fifo_delete(fifos->stdout_name);
console_fifo_delete(fifos->stderr_name);
free_command_fifo_config(fifos);
return -1;
}
struct console_loop_thread_args {
struct command_fifo_config *fifo_config;
bool tty;
};
static void *client_console_loop_thread(void *arg)
{
int ret = 0;
int fifoinfd = -1;
int fifooutfd = -1;
int fifoerrfd = -1;
const struct console_loop_thread_args *args = arg;
bool tty = args->tty;
struct command_fifo_config *fifo_config = args->fifo_config;
sem_t *wait_open = fifo_config->wait_open;
sem_t *wait_exit = fifo_config->wait_exit;
ret = pthread_detach(pthread_self());
if (ret != 0) {
CRIT("Start: set thread detach fail");
goto err1;
}
if (fifo_config->stdin_name) {
if (console_fifo_open_withlock(fifo_config->stdin_name, &fifoinfd, O_RDWR | O_NONBLOCK)) {
ERROR("Start: failed to open console fifo.");
goto err2;
}
INFO("FIFO:%s open success for start.", fifo_config->stdin_name);
}
if (fifo_config->stdout_name) {
if (console_fifo_open(fifo_config->stdout_name, &fifooutfd, O_RDONLY | O_NONBLOCK)) {
ERROR("Failed to open console fifo.");
goto err2;
}
INFO("FIFO:%s open success for start.", fifo_config->stdout_name);
}
if (fifo_config->stderr_name) {
if (console_fifo_open(fifo_config->stderr_name, &fifoerrfd, O_RDONLY | O_NONBLOCK)) {
ERROR("Start: failed to open console fifo.");
goto err2;
}
INFO("FIFO:%s open success for start.", fifo_config->stderr_name);
}
sem_post(wait_open);
client_console_loop(0, 1, 2, fifoinfd, fifooutfd, fifoerrfd, 1, tty);
err2:
if (fifoinfd >= 0) {
console_fifo_close(fifoinfd);
}
if (fifooutfd >= 0) {
console_fifo_close(fifooutfd);
}
if (fifoerrfd >= 0) {
console_fifo_close(fifoerrfd);
}
err1:
sem_post(wait_open);
sem_post(wait_exit);
return NULL;
}
int start_client_console_thread(struct command_fifo_config *console_fifos, bool tty)
{
int res = 0;
pthread_t a_thread;
struct console_loop_thread_args args;
args.fifo_config = console_fifos;
args.tty = tty;
res = pthread_create(&a_thread, NULL, client_console_loop_thread, (void *)(&args));
if (res != 0) {
CRIT("Thread creation failed");
return -1;
}
sem_wait(console_fifos->wait_open);
return 0;
}
2019-11-06 19:33:20 +08:00