فهرست منبع

:new: pwd命令

fslongjin 2 سال پیش
والد
کامیت
8246c1c9e2
9فایلهای تغییر یافته به همراه468 افزوده شده و 67 حذف شده
  1. 2 1
      .vscode/settings.json
  2. 2 0
      kernel/common/printk.c
  3. 2 2
      user/Makefile
  4. 5 2
      user/apps/shell/Makefile
  5. 166 0
      user/apps/shell/cmd.c
  6. 120 0
      user/apps/shell/cmd.h
  7. 139 61
      user/apps/shell/shell.c
  8. 1 1
      user/apps/shell/shell.lds
  9. 31 0
      user/libs/libc/string.h

+ 2 - 1
.vscode/settings.json

@@ -99,7 +99,8 @@
         "arch.h": "c",
         "elf.h": "c",
         "stdio.h": "c",
-        "wait_queue.h": "c"
+        "wait_queue.h": "c",
+        "stddef.h": "c"
     },
     "C_Cpp.errorSquiggles": "Enabled",
     "esbonio.sphinx.confDir": ""

+ 2 - 0
kernel/common/printk.c

@@ -119,6 +119,7 @@ void auto_newline()
     if (pos.x > pos.max_x)
     {
 #ifdef DEBUG
+        uart_send(COM1, '\r');
         uart_send(COM1, '\n');
 #endif
         pos.x = 0;
@@ -127,6 +128,7 @@ void auto_newline()
     if (pos.y > pos.max_y)
     {
 #ifdef DEBUG
+        uart_send(COM1, '\r');
         uart_send(COM1, '\n');
 #endif
         pos.y = pos.max_y;

+ 2 - 2
user/Makefile

@@ -24,7 +24,7 @@ all:
 	$(shell if [ ! -e $(tmp_output_dir) ];then mkdir -p $(tmp_output_dir); fi)
 	$(shell if [ ! -e $(output_dir) ];then mkdir -p $(output_dir); fi)
 
-	$(MAKE) sys_api_lib
+# $(MAKE) sys_api_lib
 	$(MAKE) shell
 # objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O binary sys_api_lib $(ROOT_PATH)/bin/user/init.bin
 #objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O elf64-x86-64 sys_api_lib $(ROOT_PATH)/bin/user/init.bin
@@ -35,7 +35,7 @@ sys_api_lib:
 #ld -b elf64-x86-64 -z muldefs -o sys_api_lib init.o $(shell find . -name "*.o") -T init.lds
 
 shell:
-	ld -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/shell  $(shell find ./apps/shell -name "*.o") $(shell find ./libs -name "*.o")
+	ld -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/shell  $(shell find ./apps/shell -name "*.o") $(shell find ./libs -name "*.o") -T ./apps/shell/shell.lds
 
 	objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O elf64-x86-64 $(tmp_output_dir)/shell $(output_dir)/shell.elf
 clean: 

+ 5 - 2
user/apps/shell/Makefile

@@ -1,4 +1,7 @@
-all: shell.o
+all: shell.o cmd.o
 
 shell.o: shell.c
-	gcc $(CFLAGS) -c shell.c  -o shell.o
+	gcc $(CFLAGS) -c shell.c  -o shell.o
+
+cmd.o: cmd.c
+	gcc $(CFLAGS) -c cmd.c  -o cmd.o

+ 166 - 0
user/apps/shell/cmd.c

@@ -0,0 +1,166 @@
+#include "cmd.h"
+#include <libc/string.h>
+#include <libc/stdio.h>
+#include <libc/stddef.h>
+
+// 当前工作目录(在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},
+
+};
+// 总共的内建命令数量
+const static int total_built_in_cmd_num = sizeof(shell_cmds) / sizeof(struct built_in_cmd_t);
+
+/**
+ * @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
+ */
+// todo:
+int shell_cmd_cd(int argc, char **argv) {}
+
+/**
+ * @brief 查看文件夹下的文件列表
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+// todo:
+int shell_cmd_ls(int argc, char **argv) {}
+
+/**
+ * @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);
+}
+
+/**
+ * @brief 查看文件内容的命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+// todo:
+int shell_cmd_cat(int argc, char **argv) {}
+
+/**
+ * @brief 创建空文件的命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+// todo:
+int shell_cmd_touch(int argc, char **argv) {}
+
+/**
+ * @brief 删除命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+// todo:
+int shell_cmd_rm(int argc, char **argv) {}
+
+/**
+ * @brief 创建文件夹的命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+// todo:
+int shell_cmd_mkdir(int argc, char **argv) {}
+
+/**
+ * @brief 删除文件夹的命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+// todo:
+int shell_cmd_rmdir(int argc, char **argv) {}
+
+/**
+ * @brief 执行新的程序的命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+
+// todo:
+int shell_cmd_exec(int argc, char **argv) {}
+
+/**
+ * @brief 重启命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+// todo:
+int shell_cmd_reboot(int argc, char **argv) {}

+ 120 - 0
user/apps/shell/cmd.h

@@ -0,0 +1,120 @@
+#pragma once
+
+/**
+ * @brief shell内建命令结构体
+ * 
+ */
+struct built_in_cmd_t
+{
+    char *name;
+    int (*func)(int argc, char **argv);
+};
+
+extern struct built_in_cmd_t shell_cmds[];
+/**
+ * @brief 寻找对应的主命令编号
+ *
+ * @param main_cmd 主命令
+ * @return int 主命令编号
+ */
+int shell_find_cmd(char *main_cmd);
+
+
+/**
+ * @brief 运行shell内建的命令
+ *
+ * @param index 主命令编号
+ * @param argc 参数数量
+ * @param argv 参数列表
+ */
+void shell_run_built_in_command(int index, int argc, char **argv);
+
+/**
+ * @brief cd命令:进入文件夹
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+int shell_cmd_cd(int argc, char **argv);
+
+/**
+ * @brief 查看文件夹下的文件列表
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+int shell_cmd_ls(int argc, char **argv);
+
+/**
+ * @brief 显示当前工作目录的命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+int shell_cmd_pwd(int argc, char **argv);
+
+/**
+ * @brief 查看文件内容的命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+int shell_cmd_cat(int argc, char **argv);
+
+/**
+ * @brief 创建空文件的命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+int shell_cmd_touch(int argc, char **argv);
+
+/**
+ * @brief 删除命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+int shell_cmd_rm(int argc, char **argv);
+
+/**
+ * @brief 创建文件夹的命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+int shell_cmd_mkdir(int argc, char **argv);
+
+/**
+ * @brief 删除文件夹的命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+int shell_cmd_rmdir(int argc, char **argv);
+
+/**
+ * @brief 执行新的程序的命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+int shell_cmd_exec(int argc, char **argv);
+
+/**
+ * @brief 重启命令
+ *
+ * @param argc
+ * @param argv
+ * @return int
+ */
+int shell_cmd_reboot(int argc, char **argv);

+ 139 - 61
user/apps/shell/shell.c

@@ -3,81 +3,159 @@
 #include <libc/fcntl.h>
 #include <libc/stdlib.h>
 #include <libKeyboard/keyboard.h>
-int main()
+#include <libc/string.h>
+#include <libc/stddef.h>
+
+#include "cmd.h"
+
+#define pause_cpu() asm volatile("pause\n\t");
+
+/**
+ * @brief 循环读取每一行
+ *
+ * @param fd 键盘文件描述符
+ * @param buf 输入缓冲区
+ * @return 读取的字符数
+ */
+#define INPUT_BUFFER_SIZE 512
+int shell_readline(int fd, char *buf);
+
+extern char *shell_current_path;
+
+/**
+ * @brief 解析shell命令
+ *
+ * @param buf 输入缓冲区
+ * @param argc 返回值:参数数量
+ * @param argv 返回值:参数列表
+ * @return int
+ */
+int parse_command(char *buf, int *argc, char ***argv);
+
+/**
+ * @brief shell主循环
+ *
+ * @param kb_fd 键盘文件描述符
+ */
+static void main_loop(int kb_fd)
 {
-    char string[] = "/333.txt";
-    uint8_t buf[128] = {0};
-    char tips_str[] = "The first application 'init.bin' started successfully!\n";
-    put_string(tips_str, COLOR_GREEN, COLOR_BLACK);
+    unsigned char input_buffer[INPUT_BUFFER_SIZE] = {0};
 
-    printf("test printf: %s size: %d\n", string, sizeof(string));
+    // 初始化当前工作目录的路径
+    shell_current_path = (char *)malloc(256);
+    memset(shell_current_path, 0, 256);
+    shell_current_path = "/";
 
-    char kb_file_path[] = "/dev/keyboard.dev";
-    int kb_fd = open(kb_file_path, 0);
-    printf("keyboard fd = %d\n", kb_fd);
+    // shell命令行的主循环
     while (true)
     {
-        int key = keyboard_analyze_keycode(kb_fd);
-        if(key)
-            printf("%c", (char)key);
-    }
-    
-    
-    /*
-    int fd = open(string, 0);
-    printf("fd=%d\n", fd);
+        int argc = 0;
+        char **argv;
 
-    read(fd, buf, 128);
+        printf("[DragonOS] # ");
+        memset(input_buffer, 0, INPUT_BUFFER_SIZE);
 
-    put_string(buf, COLOR_ORANGE, COLOR_BLACK);
+        // 循环读取每一行到buffer
+        shell_readline(kb_fd, input_buffer);
 
-    lseek(fd, 0, SEEK_SET);
-    write(fd, tips_str, sizeof(tips_str)-1);
-    lseek(fd, 0, SEEK_SET);
+        int cmd_num = parse_command(input_buffer, &argc, &argv);
+        printf("\n");
+        if (cmd_num >= 0)
+            shell_run_built_in_command(cmd_num, argc, argv);
+        
+    }
+}
 
-    // 由于暂时没有实现用户态的memset,因此先手动清零
-    for(int i=0;i<128;++i)
-        buf[i] = 0;
+int main()
+{
+    // 打开键盘文件
+    char kb_file_path[] = "/dev/keyboard.dev";
+    int kb_fd = open(kb_file_path, 0);
+    // printf("keyboard fd = %d\n", kb_fd);
 
-    read(fd, buf, 128);
-    put_string(buf, COLOR_YELLOW, COLOR_BLACK);
-    close(fd);
-    
+    main_loop(kb_fd);
+    while (1)
+        ;
+}
+
+/**
+ * @brief 循环读取每一行
+ *
+ * @param fd 键盘文件描述符
+ * @param buf 输入缓冲区
+ * @return 读取的字符数
+ */
+int shell_readline(int fd, char *buf)
+{
+    int key = 0;
+    int count = 0;
 
-    void *ptr[256] = {0};
-    for (int k = 0; k < 2; ++k)
+    while (1)
     {
-        printf("try to malloc 256*1M=256MB\n");
-        uint64_t js = 0;
-        for (int i = 0; i < 256; ++i)
-        {
-            ptr[i] = malloc(1024 * 1024);
-            js += *(uint64_t *)((uint64_t)(ptr[i]) - sizeof(uint64_t));
-            // if (*(uint64_t *)((uint64_t)(ptr[i]) - sizeof(uint64_t)) > 0x4008)
-            //     printf("[%ld] start_addr = %#018lx, len = %#010lx\n", i, (uint64_t)(ptr[i]) - 8, *(uint64_t *)((uint64_t)(ptr[i]) - sizeof(uint64_t)));
-        }
+        key = keyboard_analyze_keycode(fd);
+        if (key == '\n')
+            return count;
 
-        // printf("ptr[0]->len=%lld\n", *(uint64_t *)((uint64_t)ptr[0] - sizeof(uint64_t)));
-        // printf("ptr[1]->len=%lld\n", *(uint64_t *)((uint64_t)ptr[1] - sizeof(uint64_t)));
-        //  printf("ptr[24]->len=%lld\n", *(uint64_t*)((uint64_t)ptr[24] - sizeof(uint64_t)));
-        printf("alloc done. total used: %lld bytes\n", js);
-        printf("try to free...\n");
-        for (int i = 0; i < 256; ++i)
+        if (key)
         {
-            free(ptr[i]);
+            buf[count++] = key;
+            printf("%c", key);
         }
-        printf("free done!\n");
+
+        // 输入缓冲区满了之后,直接返回
+        if (count >= INPUT_BUFFER_SIZE - 1)
+            return count;
+
+        pause_cpu();
     }
-    */
-    
-
-    // *p = 'a';
-    /*
-    pid_t p = fork();
-    if(p == 0)
-        put_string("subproc\n", COLOR_PURPLE, COLOR_BLACK);
-    else put_string("parent proc\n", COLOR_ORANGE, COLOR_BLACK);
-*/
-    while (1)
-        ;
+}
+
+/**
+ * @brief 解析shell命令
+ *
+ * @param buf 输入缓冲区
+ * @param argc 返回值:参数数量
+ * @param argv 返回值:参数列表
+ * @return int 主命令的编号
+ */
+int parse_command(char *buf, int *argc, char ***argv)
+{
+    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);
 }

+ 1 - 1
user/apps/shell/shell.lds

@@ -13,7 +13,7 @@ SECTIONS
 	{
 		_text = .;
 		
-		init.o(.text)
+		*(.text)
 		
 		_etext = .;
 	}

+ 31 - 0
user/libs/libc/string.h

@@ -34,4 +34,35 @@ size_t strlen(const char *s)
         ++__res;
     }
     return __res;
+}
+
+
+/*
+        比较字符串 FirstPart and SecondPart
+        FirstPart = SecondPart =>  0
+        FirstPart > SecondPart =>  1
+        FirstPart < SecondPart => -1
+*/
+
+int strcmp(const char *FirstPart, const char *SecondPart)
+{
+    register int __res;
+    __asm__ __volatile__("cld	\n\t"
+                         "1:	\n\t"
+                         "lodsb	\n\t"
+                         "scasb	\n\t"
+                         "jne	2f	\n\t"
+                         "testb	%%al,	%%al	\n\t"
+                         "jne	1b	\n\t"
+                         "xorl	%%eax,	%%eax	\n\t"
+                         "jmp	3f	\n\t"
+                         "2:	\n\t"
+                         "movl	$1,	%%eax	\n\t"
+                         "jl	3f	\n\t"
+                         "negl	%%eax	\n\t"
+                         "3:	\n\t"
+                         : "=a"(__res)
+                         : "D"(FirstPart), "S"(SecondPart)
+                         :);
+    return __res;
 }