北航操作系统shell挑战性任务实验报告

2025-06-25

实现了一个支持多个指令的shell

1. 相对路径

  • 在内核态中开一个大数组,存储每个进程对应的当前路径
char curpath[NENV][MAXPATHLEN] = {0};
struct Var var[NENV][MAXVARNUM];
  • 新增系统调用,读写当前进程的当前路径
void sys_get_curpath(char *s) { strcpy(s, curpath[curenv->env_id >> 11]); }

void sys_set_curpath(char *s) { strcpy(curpath[curenv->env_id >> 11], s); }
  • 在进程初始化时,给进程的当前路径设置初值
void env_init(void) {
    int i;
    /* Step 1: Initialize 'env_free_list' with 'envs[0]' ~ 'envs[NENV-1]'. */
    LIST_INIT(&env_free_list);
    TAILQ_INIT(&env_sched_list);
    for (i = NENV - 1; i >= 0; --i) {
        envs[i].env_status = ENV_FREE;
        LIST_INSERT_HEAD(&env_free_list, &envs[i], env_link);
        strcpy(curpath[i], "/");
    }
  • 新创建进程时,继承其父进程的相对路径
    e->env_id = mkenvid(e);
    e->env_parent_id = parent_id;
    u_int new_index = e->env_id >> 11;
    u_int parent_index = parent_id >> 11;
    strcpy(curpath[new_index], curpath[parent_index]);
    for (int i = 0; i < MAXVARNUM; i++) {
        struct Var temp = var[parent_index][i];
        if (temp.valid == 1 && temp.x == 1) {
            set_env_var(e->env_id, temp.key, temp.value, temp.r, temp.x);
        }
    }
  • 新增一个从相对路径到绝对路径的转换函数
void tackle_path(const char *in, char *out) {
    char temp[MAXPATHLEN] = {0};
    char cur[MAXPATHLEN] = {0};
    strcpy(temp, in);
    int len = strlen(temp);
    syscall_get_curpath(cur);
    int curlen = strlen(cur);
    if (len > 1 && temp[len - 1] == '/') {
        temp[len - 1] = '\0';
        len--;
    }
    if (len > 2 && temp[len - 1] == 'b' && temp[len - 2] == '.') {
        strcpy(out, temp);
    } else if (temp[0] == '/') {
        strcpy(out, temp);
    } else if (temp[0] == '.' && temp[1] == '.') {
        int slash = -1;
        for (int i = curlen - 1; i >= 0; i--) {
            if (cur[i] == '/') {
                slash = i;
                break;
            }
        }
        int i = 0, pos = 0;
        if (slash <= 0) {
            out[pos++] = '/';
        } else {
            for (; i < slash; i++) {
                out[pos++] = cur[i];
            }
        }
        if (out[pos - 1] != '/') {
            out[pos++] = '/';
        }
        for (i = 3; temp[i] == '.' || temp[i] == '/'; i++)
            ;
        for (; temp[i]; i++) {
            out[pos++] = temp[i];
        }
        if (out[pos - 1] == '/' && pos != 1) {
            out[pos - 1] = '\0';
        } else {
            out[pos] = '\0';
        }
    } else if (temp[0] == '.' && (temp[1] == '/' || temp[1] == '\0')) {
        int i = 0, pos = 0;
        for (; cur[i]; i++) {
            out[pos++] = cur[i];
        }
        if (out[pos - 1] != '/') {
            out[pos++] = '/';
        }
        for (i = 2; temp[i]; i++) {
            out[pos++] = temp[i];
        }
        if (out[pos - 1] == '/' && pos != 1) {
            out[pos - 1] = '\0';
        } else {
            out[pos] = '\0';
        }
    } else {
        int i = 0, pos = 0;
        for (i = 0; cur[i]; i++) {
            out[pos++] = cur[i];
        }
        if (out[pos - 1] != '/') {
            out[pos++] = '/';
        }
        for (i = 0; temp[i]; i++) {
            out[pos++] = temp[i];
        }
        if (out[pos - 1] == '/' && pos != 1) {
            out[pos - 1] = '\0';
        } else {
            out[pos] = '\0';
        }
    }
}
  • 在打开和删除文件的函数中,将传入的路径转换成绝对路径
int open(const char *path, int mode) {
    int r;
    char out[MAXPATHLEN] = {0};
    tackle_path(path, out);
    // Step 1: Alloc a new 'Fd' using 'fd_alloc' in fd.c.
    // Hint: return the error code if failed.
    struct Fd *fd;
    if ((r = fd_alloc(&fd)) < 0) {
        return r;
    }

    // Step 2: Prepare the 'fd' using 'fsipc_open' in fsipc.c.
    r = fsipc_open((const char *)out, mode, fd);
    if (r) {
        return r;
    }
...
}

int remove(const char *path) {
    // Call fsipc_remove.
    char out[MAXPATHLEN] = {0};
    tackle_path(path, out);
    return fsipc_remove((const char *)out);
}
  • 实现内建指令的外部指令的分离
void run_outer_cmd(char *s) {
    int fork_id = fork();
    if (fork_id < 0) {
        debugf("fork error: %d\n", fork_id);
        return;
    }
    if (fork_id == 0) {
        gettoken(s, 0);

        char *argv[MAXARGS];
        int rightpipe = 0;
        int argc = parsecmd(argv, &rightpipe);
        if (argc == 0) {
            return;
        }
        argv[argc] = 0;
        int child = spawn(argv[0], argv);
        if (child >= 0) {
            u_int caller;
            int res = ipc_recv(&caller, 0, 0);
            if (conditional) {
                u_int parent = syscall_get_parent();
                ipc_send(parent, res, 0, 0);
            }
            close_all();
            wait(child);
        } else {
            debugf("spawn %s: %d\n", argv[0], child);
        }
        if (rightpipe) {
            wait(rightpipe);
        }
        exit();
    } else {
        wait(fork_id);
    }
    return;
}

void run_inner_cmd(char *s) {
    gettoken(s, 0);
    char *argv[MAXARGS];
    int rightpipe = 0;
    int argc = parsecmd(argv, &rightpipe);
    if (argc == 0) {
        return;
    }
    argv[argc] = 0;
    char buffer[MAXPATHLEN + 1] = {0};
...
}


void runcmd(char *s) {
    int inner = judge_inner(s);
    if (inner) {
        run_inner_cmd(s);
    } else {
        run_outer_cmd(s);
    }
}
  • 通过系统调用,实现内建指令cd和pwd
    } else if ((strcmp(argv[0], "cd") == 0) || (strcmp(argv[0], "cd.b") == 0)) {
        if (argc == 1) {
            strcpy(buffer, "/");
        } else if (argc > 2) {
            printf("Too many args for cd command\n");
            return;
        } else {
            struct Stat st;
            tackle_path((const char *)argv[1], buffer);
            if ((fd = open(buffer, O_RDONLY)) < 0) {
                printf("cd: The directory '%s' does not exist\n", argv[1]);
                return;
            }
            close(fd);
            stat(buffer, &st);
            if (!st.st_isdir) {
                printf("cd: '%s' is not a directory\n", argv[1]);
                return;
            }
        }
        syscall_set_curpath(buffer);
    } else if ((strcmp(argv[0], "pwd") == 0) ||
               (strcmp(argv[0], "pwd.b") == 0)) {
        if (argc > 1) {
            printf("pwd: expected 0 arguments; got %d\n", argc - 1);
            return;
        }
        syscall_get_curpath(buffer);
        printf("%s\n", buffer);

2. 新增指令

  • 创建目录
#include <lib.h>

int mkdir(char *path, int p) {
    int fd;
    if (p) {
        if ((fd = open(path, O_RDONLY)) >= 0) {
            close(fd);
            return 0;
        }
        int i = 0;
        char str[1024];
        for (int i = 0; path[i] != '\0'; i++) {
            if (path[i] == '/') {
                str[i] = '\0';
                if ((fd = open(path, O_RDONLY)) >= 0) {
                    close(fd);
                } else {
                    break;
                }
            }
            str[i] = path[i];
        }
        for (; path[i] != '\0'; i++) {
            if (path[i] == '/') {
                str[i] = '\0';
                fd = open(str, O_MKDIR);
                if (fd >= 0) {
                    close(fd);
                }
            }
            str[i] = path[i];
        }
        str[i] = '\0';
        fd = open(str, O_MKDIR);
        if (fd >= 0) {
            close(fd);
        }
    } else {
        if ((fd = open(path, O_RDONLY)) >= 0) {
            close(fd);
            printf("mkdir: cannot create directory '%s': File exists\n", path);
            return 1;
        }
        fd = open(path, O_MKDIR);
        if (fd == -10) {
            printf("mkdir: cannot create directory '%s': No such file or "
                   "directory\n",
                   path);
            return 1;
        } else if (fd >= 0) {
            close(fd);
        }
    }
    return 0;
}

int main(int argc, char **argv) {
    int p = 0;

    ARGBEGIN {
    case 'p':
        p = 1;
        break;
    }
    ARGEND

    int res = 0;
    if (argc == 0) {
        return 1;
    } else {
        for (int i = 0; i < argc; i++) {
            if (argv[i] == 0) {
                continue;
            }
            res += mkdir(argv[i], p);
        }
    }
    return res;
}
  • 创建文件
#include <lib.h>

int touch(char *path) {
    int fd;
    if ((fd = open(path, O_RDONLY)) >= 0) {
        close(fd);
        return 0;
    }
    fd = open(path, O_CREAT);
    if (fd == -10) {
        printf("touch: cannot touch '%s': No such file or directory\n", path);
        return 1;
    } else if (fd >= 0) {
        close(fd);
    }
    return 0;
}

int main(int argc, char **argv) {
    int res = 0;
    if (argc < 2) {
        return 1;
    } else {
        for (int i = 1; i < argc; i++) {
            res += touch(argv[i]);
        }
    }
    return res;
}
  • 删除文件
#include <lib.h>

int rm(char *path, int r, int f) {
    int fd;
    struct Stat st;
    if ((fd = open(path, O_RDONLY)) < 0) {
        if (!f) {
            printf("rm: cannot remove '%s': No such file or directory\n", path);
        }
        return 1;
    }
    close(fd);
    stat(path, &st);
    if (st.st_isdir && !r) {
        printf("rm: cannot remove '%s': Is a directory\n", path);
        return 1;
    }
    remove(path);
    return 0;
}

int main(int argc, char **argv) {
    int r = 0, f = 0;

    ARGBEGIN {
    case 'r':
        r = 1;
        break;
    case 'f':
        f = 1;
        break;
    }
    ARGEND

    int res = 0;
    if (argc == 0) {
        return 1;
    } else {
        for (int i = 0; i < argc; i++) {
            if (argv[i] == 0) {
                continue;
            }
            res += rm(argv[i], r, f);
        }
    }
    return res;
}

3. 环境变量

  • 在内核态中开一个大数组,存储每个进程对应的环境变量
struct Var {
    char key[MAXVARLEN];
    char value[MAXVARLEN];
    int r;
    int x;
    int valid;
};
...
extern char curpath[NENV][MAXPATHLEN];
extern struct Var var[NENV][MAXVARNUM];
  • 新增系统调用,读写和打印当前进程的环境变量
void set_env_var(u_int envid, char *key, char *value, int r, int x) {
    int index = envid >> 11;
    for (int i = 0; i < MAXVARNUM; i++) {
        if (strcmp(var[index][i].key, key) == 0 && var[index][i].valid == 1) {
            if (var[index][i].r == 0) {
                strcpy(var[index][i].value, value);
                var[index][i].r = r;
                var[index][i].x = x;
            }
            return;
        }
    }
    for (int i = 0; i < MAXVARNUM; i++) {
        if (var[index][i].valid == 0) {
            strcpy(var[index][i].key, key);
            strcpy(var[index][i].value, value);
            var[index][i].valid = 1;
            var[index][i].r = r;
            var[index][i].x = x;
            return;
        }
    }
}

void get_env_var(u_int envid, char *key, char *res) {
    int index = envid >> 11;
    for (int i = 0; i < MAXVARNUM; i++) {
        if (strcmp(var[index][i].key, key) == 0 && var[index][i].valid == 1) {
            strcpy(res, var[index][i].value);
            return;
        }
    }
}

void unset_env_var(u_int envid, char *key) {
    int index = envid >> 11;
    for (int i = 0; i < MAXVARNUM; i++) {
        if (strcmp(var[index][i].key, key) == 0 && var[index][i].valid == 1) {
            if (var[index][i].r == 0) {
                strcpy(var[index][i].key, "\0");
                strcpy(var[index][i].value, "\0");
                var[index][i].r = 0;
                var[index][i].x = 0;
                var[index][i].valid = 0;
            }
            return;
        }
    }
}

void print_env_var(u_int envid) {
    int index = envid >> 11;
    for (int i = 0; i < MAXVARNUM; i++) {
        if (var[index][i].valid == 1) {
            printk("%s=%s\n", var[index][i].key, var[index][i].value);
        }
    }
}
  • 新创建进程时,继承其父进程的全局环境变量‘
int env_alloc(struct Env **new, u_int parent_id) {
...
    e->env_id = mkenvid(e);
    e->env_parent_id = parent_id;
    u_int new_index = e->env_id >> 11;
    u_int parent_index = parent_id >> 11;
    strcpy(curpath[new_index], curpath[parent_index]);
    for (int i = 0; i < MAXVARNUM; i++) {
        struct Var temp = var[parent_index][i];
        if (temp.valid == 1 && temp.x == 1) {
            set_env_var(e->env_id, temp.key, temp.value, temp.r, temp.x);
        }
    }
...
}
  • 在获取当前token的函数中,展开环境变量的引用
    if (*s == '$') {
        char key[MAXVARLEN];
        char value[MAXVARLEN];
        char after[1024];
        int i;
        for (i = 1; s[i] && strchr(CHAR, s[i]); i++) {
            key[i - 1] = s[i];
        }
        key[i - 1] = '\0';
        strcpy(after, s + i);
        syscall_get_var(key, value);
        strcpy(s, value);
        strcpy(s + strlen(value), after);
        *p1 = s;
        s += strlen(value);
        while (s[0] && !strchr(WHITESPACE, s[0])) {
            s++;
        }
        *p2 = s;
        return 'w';
    }
  • 通过系统调用,实现内建指令declare和unset
    } else if ((strcmp(argv[0], "declare") == 0) ||
               (strcmp(argv[0], "declare.b") == 0)) {
        int r = 0, x = 0;
        char value[MAXVARLEN] = {0};
        char key[MAXVARLEN] = {0};
        if (argc == 1) {
            syscall_print_var();
            return;
        } else if (argc > 3) {
            return;
        } else if (argc == 3) {
            if (strcmp(argv[1], "-r") == 0) {
                r = 1;
            } else if (strcmp(argv[1], "-x") == 0) {
                x = 1;
            } else if ((strcmp(argv[1], "-xr") == 0) ||
                       (strcmp(argv[1], "-rx") == 0)) {
                r = 1, x = 1;
            }
        }
        int i = 0, pos = 0;
        for (; argv[argc - 1][i] && argv[argc - 1][i] != '='; i++) {
            key[pos++] = argv[argc - 1][i];
        }
        key[pos] = '\0';
        pos = 0;
        i++;
        for (; argv[argc - 1][i]; i++) {
            value[pos++] = argv[argc - 1][i];
        }
        syscall_set_var(key, value, r, x);
    } else if ((strcmp(argv[0], "unset") == 0) ||
               (strcmp(argv[0], "unset.b") == 0)) {
        if (argc != 2) {
            return;
        }
        syscall_unset_var(argv[1]);
    }

4. 注释

  • 在指令输入后,将指令井号后部分截断后执行
        if (buf[0] == '\0' || buf[0] == '#') {
            continue;
        }
        for (int i = 0; i < strlen(buf); i++) {
            if (buf[i] == '#') {
                buf[i] = '\0';
            }
        }

5. 指令输入优化

  • 删除读取字符的不必要循环
int sys_cgetc(void) {
    int ch = scancharc();
    return ch;
}
  • 实现指令的重新打印展示
void redisplay_line(char *buf, int len, int cursor) {
    printf("\r$ ");
    for (int i = 0; i < len; i++) {
        printf("%c", buf[i]);
    }
    printf("\033[K");
    if (cursor < len) {
        printf("\r$ ");
        for (int i = 0; i < cursor; i++) {
            printf("%c", buf[i]);
        }
    }
}
  • 修改读取键盘输入的函数
void readline(char *buf, u_int n) {
    int r;
    int pos = 0;
    int len = 0;
    memset(buf, 0, n);
    history_current = -1;
    memset(current_input, 0, sizeof(current_input));
    while (1) {
        char c;
        if ((r = read(0, &c, 1)) != 1) {
            if (r < 0) {
                debugf("read error: %d\n", r);
            }
            exit();
        }
        if (c == '\r' || c == '\n') {
            buf[len] = '\0';
            return;
        } else if (c == '\b' || c == 0x7f) {
            if (pos > 0) {
                for (int i = pos - 1; i < len - 1; i++) {
                    buf[i] = buf[i + 1];
                }
                pos--;
                len--;
                buf[len] = '\0';
                redisplay_line(buf, len, pos);
            }
        } else if (c == 1) {
            pos = 0;
            printf("\r$ ");
        } else if (c == 5) {
            pos = len;
            printf("\r$ ");
            for (int i = 0; i < len; i++) {
                printf("%c", buf[i]);
            }
        } else if (c == 11) {
            len = pos;
            buf[len] = '\0';
            redisplay_line(buf, len, pos);
        } else if (c == 21) {
            if (pos > 0) {
                for (int i = 0; i < len - pos; i++) {
                    buf[i] = buf[pos + i];
                }
                len = len - pos;
                pos = 0;
                buf[len] = '\0';
                redisplay_line(buf, len, pos);
            }
        } else if (c == 23) {
            if (pos > 0) {
                int old_pos = pos;
                while (pos > 0 &&
                       (buf[pos - 1] == ' ' || buf[pos - 1] == '\t')) {
                    pos--;
                }
                while (pos > 0 && buf[pos - 1] != ' ' && buf[pos - 1] != '\t') {
                    pos--;
                }
                int delete = old_pos - pos;
                for (int i = pos; i < len - delete; i++) {
                    buf[i] = buf[i + delete];
                }
                len -= delete;
                buf[len] = '\0';
                redisplay_line(buf, len, pos);
            }
        } else if (c == 27) {
            char seq[3];
            if (read(0, &seq[0], 1) == 1 && seq[0] == '[') {
                if (read(0, &seq[1], 1) == 1) {
                    if (seq[1] == 'A') {
                        if (history_count > 0) {
    
                            if (history_current == -1) {
                                strcpy(current_input, buf);
                                history_current = history_count - 1;
                            } else if (history_current > 0) {
                                history_current--;
                            }
                            strcpy(buf, history_lines[history_current]);
                            len = strlen(buf);
                            pos = len;
                            printf("\r$ ");
                            for (int i = 0; i < len; i++) {
                                printf("%c", buf[i]);
                            }
                            printf("\033[K");
                        }
                    } else if (seq[1] == 'B') {
                        if (history_current != -1) {
                      
                            if (history_current < history_count - 1) {
                                history_current++;
                                strcpy(buf, history_lines[history_current]);
                            } else {
                                history_current = -1;
                                strcpy(buf, current_input);
                            }
                            len = strlen(buf);
                            pos = len;
                            printf("\r$ ");
                            for (int i = 0; i < len; i++) {
                                printf("%c", buf[i]);
                            }
                            printf("\033[K");
                        }
                    } else if (seq[1] == 'C') {
                        if (pos < len) {
                      
                            pos++;
                            printf("\033[C");
                        }
                    } else if (seq[1] == 'D') {
                        if (pos > 0) {
                      
                            pos--;
                            printf("\033[D");
                        }
                    }
                }
            }
        } else if (c >= 32 && c <= 126) {
          
            if (len < n - 1) {
                for (int i = len; i > pos; i--) {
                    buf[i] = buf[i - 1];
                }
                buf[pos] = c;
                pos++;
                len++;
                buf[len] = '\0';
                redisplay_line(buf, len, pos);
            }
        }
    }
}

6. 历史指令

  • 在创建终端时,创建或加载已有历史指令文件
    history_fd = open("/.mos_history", O_RDWR | O_CREAT);
    load_history();
  • 每次输入指令后,将新指令保存到文件中
void save_history(void) {
    if (history_fd < 0) {
        return;
    }
    close(history_fd);
    history_fd = open("/.mos_history", O_WRONLY | O_CREAT | O_TRUNC);
    if (history_fd < 0) {
        return;
    }
    for (int i = 0; i < history_count; i++) {
        write(history_fd, history_lines[i], strlen(history_lines[i]));
        write(history_fd, "\n", 1);
    }
}

void store_history(char *buf) {
    if (strlen(buf) == 0) {
        return;
    }
    int len = strlen(buf);
    if (len > 0 && buf[len - 1] == '\n') {
        buf[len - 1] = '\0';
        len--;
    }
    if (len == 0) {
        return;
    }
    if (history_count > 0 &&
        strcmp(buf, history_lines[history_count - 1]) == 0) {
        return;
    }
    if (history_count >= MAXHISTORY) {
        for (int i = 0; i < MAXHISTORY - 1; i++) {
            strcpy(history_lines[i], history_lines[i + 1]);
        }
        history_count = MAXHISTORY - 1;
    }
    strcpy(history_lines[history_count], buf);
    history_count++;
    save_history();
}

7. 追加重定向

  • 解析追加重定向符号
    if (*s == '>' && *(s + 1) == '>') {
        *p1 = s;
        *s++ = 0;
        *s++ = 0;
        *p2 = s;
        return 'a';
    }
  • 添加追加打开方式
#define O_APPEND 0x0004  /* open for appending */
  • 追加模式打开时,修改文件偏移量
    ff->f_fd.fd_omode = o->o_mode;
    ff->f_fd.fd_dev_id = devfile.dev_id;
    if (rq->req_omode & O_APPEND) {
        ff->f_fd.fd_offset = ff->f_file.f_size;
    }
  • 解析命令时,仿照普通重定向实现
        case 'a':
            if (gettoken(0, &t) != 'w') {
                exit();
            }
            if ((fd = open(t, O_RDONLY)) < 0) {
                fd = open(t, O_CREAT);
                if (fd < 0) {
                    exit();
                }
            }
            close(fd);
            if ((fd = open(t, O_WRONLY | O_APPEND)) < 0) {
                exit();
            }
            if ((r = dup(fd, 1)) < 0) {
                exit();
            }
            close(fd);

            break;

8. 条件执行

  • 解析条件执行符号
    if (*s == '|' && *(s + 1) == '|') {
        *p1 = s;
        *s++ = 0;
        *s++ = 0;
        *p2 = s;
        return 'O';
    }

    if (*s == '&' && *(s + 1) == '&') {
        *p1 = s;
        *s++ = 0;
        *s++ = 0;
        *p2 = s;
        return 'A';
    }
  • 将无返回值的外部命令改为有返回值
int cat(int f, char *s) {
    long n;
    int r;
    while ((n = read(f, buf, (long)sizeof buf)) > 0) {
        if ((r = write(1, buf, n)) != n) {
            printf("write error copying %s: %d", s, r);
            return 1;
        }
    }
    if (n < 0) {
        printf("error reading %s: %d", s, n);
        return 1;
    }
    return 0;
}
  • 捕获main函数的返回值,并传递给父进程
void libmain(int argc, char **argv) {
    // set file handles
    ...
    // set env to point at our env structure in envs[].
    env = &envs[ENVX(syscall_getenvid())];

    int res = main(argc, argv);
    u_int parent = syscall_get_parent();
    ipc_send(parent, res, 0, 0);

    // exit gracefully
    exit();
}
  • 运行外部指令时,接受返回值,并传递给父进程
        int child = spawn(argv[0], argv);
        if (child >= 0) {
            u_int caller;
            int res = ipc_recv(&caller, 0, 0);
            if (conditional) {
                u_int parent = syscall_get_parent();
                ipc_send(parent, res, 0, 0);
            }
            close_all();
            wait(child);
  • 解析命令时,右侧指令对应进程等待左侧指令的返回值消息,决定是否执行
        case 'O':;
            fork_id = fork();
            if (fork_id < 0) {
                debugf("failed to fork in sh.c\n");
                exit();
            } else if (fork_id == 0) {
                conditional = 1;
                return argc;
            } else {
                u_int caller;
                int res = ipc_recv(&caller, 0, 0);
                if (res != 0) {
                    return parsecmd(argv, rightpipe);
                } else {
                    return 0;
                }
            }

            break;
        case 'A':;
            fork_id = fork();
            if (fork_id < 0) {
                debugf("failed to fork in sh.c\n");
                exit();
            } else if (fork_id == 0) {
                conditional = 1;
                return argc;
            } else {
                u_int caller;
                int res = ipc_recv(&caller, 0, 0);
                if (res == 0) {
                    return parsecmd(argv, rightpipe);
                } else {
                    return 0;
                }
            }
            break;
  • 实现内建exit指令
    if ((strcmp(argv[0], "exit") == 0) || (strcmp(argv[0], "exit.b") == 0)) {
        int parent = syscall_get_parent();
        ipc_send(parent, 0, 0, 0);
        exit();

9. 反引号

  • 对指令进行预处理,执行反引号内的指令,结果通过管道返回,进行字符串替换
int run_quote_cmd(char *cmd, char *output) {
    int p[2];
    if (pipe(p) < 0) {
        return -1;
    }
    int child = fork();
    if (child < 0) {
        close(p[0]);
        close(p[1]);
        return -1;
    } else if (child == 0) {
        close(p[0]);
        dup(p[1], 1);
        close(p[1]);
        runcmd(cmd);
        exit();
    } else {
        close(p[1]);
        int total = 0;
        char buffer[1024];
        int r;
        while ((r = read(p[0], buffer, sizeof(buffer))) > 0) {
            if (r > 0) {
                memcpy(output + total, buffer, r);
                total += r;
            }
        }
        close(p[0]);
        wait(child);
        output[total] = '\0';
        while (total > 0 &&
               (output[total - 1] == '\n' || output[total - 1] == '\r')) {
            output[--total] = '\0';
        }
        return total;
    }
}

void tackle_quote(char *line) {
    char result[1024] = "";
    char *dest = result;
    char *src = line;
    while (*src) {
        if (*src == '`') {
            src++;
            char *start = src;
            while (*src && *src != '`') {
                src++;
            }
            if (*src == '`') {
                int len = src - start;
                char cmd[MAXPATHLEN];
                strcpy(cmd, start);
                cmd[len] = '\0';
                char output[MAXPATHLEN];
                if (run_quote_cmd(cmd, output) >= 0) {
                    for (char *p = output; *p; p++) {
                        if (*p == '\n' || *p == '\r') {
                    
                            if (dest - result < sizeof(result) - 1) {
                                *dest++ = ' ';
                            }
                        } else {
                            if (dest - result < sizeof(result) - 1) {
          
                                *dest++ = *p;
                            }
                        }
                    }
                }
            
                src++;
            } else {
                if (dest - result < sizeof(result) - 1) {
                    *dest++ = '`';
                }
                src = start;
            }
        } else {
            if (dest - result < sizeof(result) - 1) {
                *dest++ = *src;
            }
            src++;
        }
    }
    *dest = '\0';
    strcpy(line, result);
}

10. 一行多指令

  • 递归创建新进程,执行右侧指令
        case ';':
            fork_id = fork();
            if (fork_id < 0) {
                exit();
            } else if (fork_id == 0) {
                return argc;
            } else {
                wait(fork_id);
                return parsecmd(argv, rightpipe);
            }

            break;