DragonOS/user/apps/shell/cmd.c

554 lines
12 KiB
C
Raw Normal View History

2022-05-24 08:37:28 +00:00
#include "cmd.h"
#include <libc/string.h>
#include <libc/stdio.h>
#include <libc/stddef.h>
2022-05-25 06:38:15 +00:00
#include <libsystem/syscall.h>
2022-05-25 14:50:32 +00:00
#include <libc/string.h>
#include <libc/errno.h>
#include <libc/unistd.h>
#include <libc/stdlib.h>
2022-05-30 09:39:45 +00:00
#include <libc/fcntl.h>
2022-05-29 06:36:46 +00:00
#include <libc/dirent.h>
2022-05-31 13:55:06 +00:00
#include <libc/sys/wait.h>
#include <libc/sys/stat.h>
2022-05-25 14:50:32 +00:00
#include "cmd_help.h"
2022-08-20 13:47:41 +00:00
#include "cmd_test.h"
2022-05-24 08:37:28 +00:00
// 当前工作目录在main_loop中初始化
char *shell_current_path = NULL;
/**
* @brief shell
*
*/
struct built_in_cmd_t shell_cmds[] =
{
{"cd", shell_cmd_cd},
{"cat", shell_cmd_cat},
{"exec", shell_cmd_exec},
{"ls", shell_cmd_ls},
{"mkdir", shell_cmd_mkdir},
{"pwd", shell_cmd_pwd},
{"rm", shell_cmd_rm},
{"rmdir", shell_cmd_rmdir},
{"reboot", shell_cmd_reboot},
{"touch", shell_cmd_touch},
{"about", shell_cmd_about},
2022-08-07 13:17:02 +00:00
{"free", shell_cmd_free},
2022-05-25 14:50:32 +00:00
{"help", shell_help},
2022-08-20 13:47:41 +00:00
{"pipe", shell_pipe_test},
2022-05-24 08:37:28 +00:00
};
// 总共的内建命令数量
const static int total_built_in_cmd_num = sizeof(shell_cmds) / sizeof(struct built_in_cmd_t);
2022-05-31 13:55:06 +00:00
/**
* @brief cwd与文件名进行拼接
*
* @param filename
* @param result_path_len
* @return char*
*/
static char *get_target_filepath(const char *filename, int *result_path_len)
{
int cwd_len = strlen(shell_current_path);
// 计算文件完整路径的长度
*result_path_len = cwd_len + strlen(filename);
char *file_path = (char *)malloc(*result_path_len + 2);
memset(file_path, 0, *result_path_len + 2);
strcpy(file_path, shell_current_path);
// 在文件路径中加入斜杠
if (cwd_len > 1)
file_path[cwd_len] = '/';
// 拼接完整路径
if (filename[0] == '/')
strcat(file_path, filename + 1);
else
strcat(file_path, filename);
2022-05-31 13:55:06 +00:00
return file_path;
}
2022-05-24 08:37:28 +00:00
/**
* @brief
*
* @param main_cmd
* @return int
* -1
*/
int shell_find_cmd(char *main_cmd)
{
for (int i = 0; i < total_built_in_cmd_num; ++i)
{
if (strcmp(main_cmd, shell_cmds[i].name) == 0) // 找到对应的命令号
return i;
}
// 找不到该命令
return -1;
}
/**
* @brief shell内建的命令
*
* @param index
* @param argc
* @param argv
*/
void shell_run_built_in_command(int index, int argc, char **argv)
{
if (index >= total_built_in_cmd_num)
return;
// printf("run built-in command : %s\n", shell_cmds[index].name);
shell_cmds[index].func(argc, argv);
}
/**
* @brief cd命令:
*
* @param argc
* @param argv
* @return int
*/
2022-05-25 14:50:32 +00:00
int shell_cmd_cd(int argc, char **argv)
{
int current_dir_len = strlen(shell_current_path);
if (argc < 2)
{
shell_help_cd();
goto done;
}
// 进入当前文件夹
if (!strcmp(".", argv[1]))
goto done;
// 进入父目录
if (!strcmp("..", argv[1]))
{
// 当前已经是根目录
if (!strcmp("/", shell_current_path))
goto done;
// 返回到父目录
int index = current_dir_len - 1;
for (; index > 1; --index)
{
if (shell_current_path[index] == '/')
break;
}
shell_current_path[index] = '\0';
// printf("switch to \" %s \"\n", shell_current_path);
goto done;
}
int dest_len = strlen(argv[1]);
// 路径过长
if (dest_len >= SHELL_CWD_MAX_SIZE - 1)
{
printf("ERROR: Path too long!\n");
goto fail;
}
if (argv[1][0] == '/')
{
// ======进入绝对路径=====
int ec = chdir(argv[1]);
if (ec == -1)
ec = errno;
if (ec == 0)
{
// 获取新的路径字符串
char *new_path = (char *)malloc(dest_len + 2);
memset(new_path, 0, dest_len + 2);
strncpy(new_path, argv[1], dest_len);
// 释放原有的路径字符串的内存空间
free(shell_current_path);
shell_current_path = new_path;
shell_current_path[dest_len] = '\0';
return 0;
}
else
goto fail;
; // 出错则直接忽略
2022-05-25 14:50:32 +00:00
}
else // ======进入相对路径=====
2022-05-25 14:50:32 +00:00
{
int dest_offset = 0;
if (dest_len > 2)
{
if (argv[1][0] == '.' && argv[1][1] == '/') // 相对路径
dest_offset = 2;
}
2022-05-29 06:36:46 +00:00
int new_len = current_dir_len + dest_len - dest_offset;
2022-05-25 14:50:32 +00:00
if (new_len >= SHELL_CWD_MAX_SIZE - 1)
{
printf("ERROR: Path too long!\n");
goto fail;
}
// 拼接出新的字符串
char *new_path = (char *)malloc(new_len + 2);
memset(new_path, 0, sizeof(new_path));
strncpy(new_path, shell_current_path, current_dir_len);
if (current_dir_len > 1)
new_path[current_dir_len] = '/';
strcat(new_path, argv[1] + dest_offset);
2022-05-25 14:50:32 +00:00
if (chdir(new_path) == 0) // 成功切换目录
{
free(shell_current_path);
// printf("new_path=%s, newlen= %d\n", new_path, new_len);
new_path[new_len + 1] = '\0';
2022-05-25 14:50:32 +00:00
shell_current_path = new_path;
goto done;
}
else
{
printf("ERROR: Cannot switch to directory: %s\n", new_path);
goto fail;
}
}
fail:;
done:;
// 释放参数所占的内存
free(argv);
return 0;
}
2022-05-24 08:37:28 +00:00
/**
* @brief
*
* @param argc
* @param argv
* @return int
*/
2022-05-25 14:50:32 +00:00
int shell_cmd_ls(int argc, char **argv)
{
2022-05-29 06:36:46 +00:00
struct DIR *dir = opendir(shell_current_path);
2022-05-30 09:39:45 +00:00
2022-05-29 06:36:46 +00:00
if (dir == NULL)
return -1;
struct dirent *buf = NULL;
// printf("dir=%#018lx\n", dir);
while (1)
{
buf = readdir(dir);
2022-05-30 09:39:45 +00:00
if (buf == NULL)
2022-05-29 06:36:46 +00:00
break;
2022-05-30 09:39:45 +00:00
2022-05-29 06:36:46 +00:00
int color = COLOR_WHITE;
2022-05-30 09:39:45 +00:00
if (buf->d_type & VFS_ATTR_DIR)
2022-05-29 06:36:46 +00:00
color = COLOR_YELLOW;
2022-05-30 09:39:45 +00:00
else if (buf->d_type & VFS_ATTR_FILE)
2022-05-29 06:36:46 +00:00
color = COLOR_INDIGO;
2022-05-30 09:39:45 +00:00
2022-05-29 06:36:46 +00:00
char output_buf[256] = {0};
sprintf(output_buf, "%s ", buf->d_name);
put_string(output_buf, color, COLOR_BLACK);
}
printf("\n");
closedir(dir);
2022-05-30 09:39:45 +00:00
2022-05-31 13:55:06 +00:00
if (argv != NULL)
2022-05-30 09:39:45 +00:00
free(argv);
2022-05-25 14:50:32 +00:00
return 0;
}
2022-05-24 08:37:28 +00:00
/**
* @brief
*
* @param argc
* @param argv
* @return int
*/
int shell_cmd_pwd(int argc, char **argv)
{
if (shell_current_path)
printf("%s\n", shell_current_path);
2022-05-31 13:55:06 +00:00
if (argv != NULL)
2022-05-30 09:39:45 +00:00
free(argv);
2022-05-24 08:37:28 +00:00
}
/**
* @brief
*
* @param argc
* @param argv
* @return int
*/
2022-05-30 09:39:45 +00:00
int shell_cmd_cat(int argc, char **argv)
{
2022-05-31 13:55:06 +00:00
int path_len = 0;
char *file_path = get_target_filepath(argv[1], &path_len);
2022-05-30 09:39:45 +00:00
// 打开文件
int fd = open(file_path, 0);
// 获取文件总大小
int file_size = lseek(fd, 0, SEEK_END);
// 将文件指针切换回文件起始位置
lseek(fd, 0, SEEK_SET);
char *buf = (char *)malloc(512);
memset(buf, 0, 512);
while (file_size > 0)
{
int l = read(fd, buf, 511);
buf[l] = '\0';
file_size -= l;
printf("%s", buf);
}
close(fd);
free(buf);
2022-05-31 13:55:06 +00:00
if (argv != NULL)
free(argv);
2022-05-30 09:39:45 +00:00
}
2022-05-24 08:37:28 +00:00
/**
* @brief
*
* @param argc
* @param argv
* @return int
*/
2022-07-06 16:55:33 +00:00
int shell_cmd_touch(int argc, char **argv)
{
int path_len = 0;
2022-07-07 02:27:40 +00:00
char *file_path;
if (argv[1][0] == '/')
file_path = argv[1];
else
file_path = get_target_filepath(argv[1], &path_len);
2022-07-06 16:55:33 +00:00
// 打开文件
int fd = open(file_path, O_CREAT);
2022-07-07 02:27:40 +00:00
switch (fd)
{
case -ENOENT:
put_string("Parent dir not exists.\n", COLOR_RED, COLOR_BLACK);
break;
default:
break;
}
2022-07-06 16:55:33 +00:00
close(fd);
if (argv != NULL)
free(argv);
}
2022-05-24 08:37:28 +00:00
/**
* @brief
*
* @param argc
* @param argv
* @return int
*/
// todo:
int shell_cmd_rm(int argc, char **argv) {}
/**
* @brief
*
* @param argc
* @param argv
* @return int
*/
int shell_cmd_mkdir(int argc, char **argv)
{
int result_path_len = -1;
const char *full_path = NULL;
if (argv[1][0] == '/')
full_path = argv[1];
else
{
full_path = get_target_filepath(argv[1], &result_path_len);
}
printf("mkdir: full_path = %s\n", full_path);
int retval = mkdir(full_path, 0);
2022-07-06 16:55:33 +00:00
if (argv != NULL)
free(argv);
2022-07-07 02:27:40 +00:00
return retval;
}
2022-05-24 08:37:28 +00:00
/**
* @brief
*
* @param argc
* @param argv
* @return int
*/
// todo:
int shell_cmd_rmdir(int argc, char **argv) {}
/**
* @brief
*
* @param argc
* @param argv
* @return int
*/
2022-05-31 13:55:06 +00:00
int shell_cmd_exec(int argc, char **argv)
{
pid_t pid = fork();
int retval = 0;
2022-06-07 15:18:26 +00:00
// printf(" pid=%d \n",pid);
2022-05-24 08:37:28 +00:00
2022-05-31 13:55:06 +00:00
if (pid == 0)
{
2022-06-07 15:18:26 +00:00
// printf("child proc\n");
2022-05-31 13:55:06 +00:00
// 子进程
int path_len = 0;
char *file_path = get_target_filepath(argv[1], &path_len);
// printf("before execv, path=%s, argc=%d\n", file_path, argc);
2022-05-31 13:55:06 +00:00
execv(file_path, argv);
free(argv);
while (1)
;
2022-05-31 13:55:06 +00:00
exit(0);
}
else
{
// printf("parent process wait for pid:[ %d ]\n", pid);
2022-05-31 13:55:06 +00:00
waitpid(pid, &retval, 0);
2022-07-12 05:20:01 +00:00
// printf("parent process wait pid [ %d ], exit code=%d\n", pid, retval);
2022-05-31 13:55:06 +00:00
free(argv);
}
}
int shell_cmd_about(int argc, char **argv)
{
if (argv != NULL)
free(argv);
int aac = 0;
char **aav;
unsigned char input_buffer[INPUT_BUFFER_SIZE] = {0};
strcpy(input_buffer, "exec /about.elf\0");
parse_command(input_buffer, &aac, &aav);
2022-05-31 13:55:06 +00:00
shell_cmd_exec(aac, aav);
2022-05-31 13:55:06 +00:00
}
2022-05-24 08:37:28 +00:00
/**
* @brief
*
* @param argc
* @param argv
* @return int
*/
2022-05-25 06:38:15 +00:00
int shell_cmd_reboot(int argc, char **argv)
{
return syscall_invoke(SYS_REBOOT, 0, 0, 0, 0, 0, 0, 0, 0);
}
2022-08-07 13:17:02 +00:00
int shell_cmd_free(int argc, char **argv)
{
int retval = 0;
if (argc == 2 && strcmp("-m", argv[1]) != 0)
{
retval = -EINVAL;
printf("Invalid argument: %s\n", argv[1]);
goto done;
}
struct mstat_t mst = {0};
retval = mstat(&mst);
if(retval!=0)
{
printf("Failed: retval=%d", retval);
goto done;
}
printf("\ttotal\tused\tfree\tshared\tcache\tavailable\n");
printf("Mem:\t");
if(argc==1) // 按照kb显示
{
printf("%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t\n", mst.total>>10,mst.used>>10,mst.free>>10, mst.shared>>10, mst.cache_used>>10, mst.available>>10);
}
else // 按照MB显示
{
printf("%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t\n", mst.total>>20,mst.used>>20,mst.free>>20, mst.shared>>20, mst.cache_used>>20, mst.available>>20);
}
done:;
if (argv != NULL)
free(argv);
return retval;
}
/**
* @brief shell命令
*
* @param buf
* @param argc
* @param argv
* @return int
*/
int parse_command(char *buf, int *argc, char ***argv)
{
// printf("parse command\n");
int index = 0; // 当前访问的是buf的第几位
// 去除命令前导的空格
while (index < INPUT_BUFFER_SIZE && buf[index] == ' ')
++index;
// 计算参数数量
for (int i = index; i < (INPUT_BUFFER_SIZE - 1); ++i)
{
// 到达了字符串末尾
if (!buf[i])
break;
if (buf[i] != ' ' && (buf[i + 1] == ' ' || buf[i + 1] == '\0'))
++(*argc);
}
// printf("\nargc=%d\n", *argc);
// 为指向每个指令的指针分配空间
*argv = (char **)malloc(sizeof(char **) * (*argc));
memset(*argv, 0, sizeof(char **) * (*argc));
// 将每个命令都单独提取出来
for (int i = 0; i < *argc && index < INPUT_BUFFER_SIZE; ++i)
{
// 提取出命令,以空格作为分割
*((*argv) + i) = &buf[index];
while (index < (INPUT_BUFFER_SIZE - 1) && buf[index] && buf[index] != ' ')
++index;
buf[index++] = '\0';
// 删除命令间多余的空格
while (index < INPUT_BUFFER_SIZE && buf[index] == ' ')
++index;
// printf("%s\n", (*argv)[i]);
}
// 以第一个命令作为主命令,查找其在命令表中的编号
return shell_find_cmd(**argv);
2022-05-25 06:38:15 +00:00
}