MIT 6.828 - 2. Lab 02: Simple xv6 shell

实验总结

  1. 本次实验用时约两个小时,使用了大量恶臭代码。

其他遇到的问题包括:

  1. 使用 dup 重定向 stdin/stdout 之后程序变得难以调试,最佳实践是使用 stderr 进行调试。

测试结果:

$ make grade
  simple echo: OK 
  simple grep: OK 
  two commands: OK 
  output redirection: OK 
  input redirection: OK 
  both redirections: OK 
  simple pipe: OK 
  pipe and redirects: OK 
  lots of commands: OK 
Score: 100/100

0. 实验准备

实验指导连接

上来直接:

$ cd xv6-riscv-fall19
$ git checkout sh

1. 代码实现

部分参考了 user/sh.c 的代码,但 sh.c 构建了 AST,接着在 AST 上执行整个流程,我使用字符串处理糊弄过关。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fcntl.h"

inline int print(int fd, char *str)
{
    return write(fd, str, strlen(str));
}

// [in-place]
// replace the left side "|" with "\0"
// then return the rest of the string or NULL
char *simple_tok(char *p, char d)
{
    while (*p != '\0' && *p != d)
        p++;
    if (*p == '\0')
        return 0;
    *p = '\0';
    return p + 1;
}


// [in-place]
// trim spaces on both side
char *trim(char *c)
{
    char *e = c;
    while (*e)
        e++;
    while (*c == ' ')
        *(c++) = '\0';
    while (*(--e) == ' ')
        ;
    *(e + 1) = '\0';
    return c;
}

void redirect(int k, int pd[])
{
    close(k);
    dup(pd[k]);
    close(pd[0]);
    close(pd[1]);
}

char cmd_buf[1024];
char *a, *n;

void handle(char *cmd)
{
    char buf[32][32];
    char *pass[32];
    int argc = 0;

    cmd = trim(cmd);
    // fprintf(2, "cmd: %s\n", cmd);

    for (int i = 0; i < 32; i++)
        pass[i] = buf[i];

    char *c = buf[argc];
    int input_pos = 0, output_pos = 0;
    for (char *p = cmd; *p; p++)
    {
        if (*p == ' ' || *p == '\n')
        {
            *c = '\0';
            argc++;
            c = buf[argc];
        }
        else {
            if(*p == '<') {
                input_pos = argc + 1;
            } if(*p == '>') {
                output_pos = argc + 1;
            }
            *c++ = *p;
        }
    }
    *c = '\0';
    argc++;
    pass[argc] = 0;

    // fprintf(2, "inpos: %d, outpos: %d\n", input_pos, output_pos);

    if(input_pos) {
        close(0);
        open(pass[input_pos], O_RDONLY);
    }

    if(output_pos) {
        close(1);
        open(pass[output_pos], O_WRONLY | O_CREATE);
    }

    char *pass2[32];
    int argc2 = 0;
    for(int pos = 0; pos < argc; pos++) {
        if(pos == input_pos - 1) pos += 2;
        if(pos == output_pos - 1) pos += 2;
        pass2[argc2++] = pass[pos];
    }
    pass2[argc2] = 0;

    if (fork())
    {
        wait(0);
    }
    else
    {
        exec(pass2[0], pass2);
    }
}

void handle_cmd()
{
    if (a)
    {
        int pd[2];
        pipe(pd);
        // int parent_pid = getpid();
        // fprintf(2, "pid: %d, cmd: %s\n", parent_pid, a);

        if(!fork()){
            // fprintf(2, "%d -> %d source\n", parent_pid, getpid());
            if(n) redirect(1, pd);
            handle(a);
        } else if(!fork()) {
            // fprintf(2, "%d -> %d sink\n", parent_pid, getpid());
            if(n) {
                redirect(0, pd);
                a = n;
                n = simple_tok(a, '|');
                handle_cmd();
            }
        }

        close(pd[0]);
        close(pd[1]);
        wait(0);
        wait(0);
    }

    exit(0);
}

// a simple shell
int main(int argc, char *argv[])
{
    while (1)
    {
        print(1, "@ ");
        memset(cmd_buf, 0, 1024);
        gets(cmd_buf, 1024);

        if (cmd_buf[0] == 0) // EOF
            exit(0);

        *strchr(cmd_buf, '\n') = '\0';

        if (fork())
        {
            wait(0);
        }
        else
        {
            a = cmd_buf;
            n = simple_tok(a, '|');
            handle_cmd();
        }
    }

    exit(0);
}
posted @ 2019-12-11 19:58  nlp-in-shell  阅读(1400)  评论(0编辑  收藏  举报