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"
|
2019-12-29 15:59:28 +08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-29 15:59:28 +08:00
|
|
|
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
|
|
|
|