-
-
Save ksvbka/08ac9ccdd21b4a5c38d70c53b8d59fd1 to your computer and use it in GitHub Desktop.
Simple shell
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * @Author: Trung Kien | |
| * @Date: 2017-03-24 23:10:01 | |
| * @Last Modified by: ksvbka | |
| * @Last Modified time: 2017-03-25 16:02:15 | |
| */ | |
| // | |
| // https://pdos.csail.mit.edu/6.828/2016/homework/sh.c | |
| // | |
| #include "mysh.h" | |
| /* Construction funciton */ | |
| struct cmd* cmd_pipe(struct cmd *left, struct cmd *right); | |
| struct cmd* cmd_redir(struct cmd *cmd, char*file, char type); | |
| struct cmd* cmd_exe(void); | |
| /* Helper funciton */ | |
| int peek(char** sbuf, char* ebuf, char* token); | |
| char* mkcopy(char *s, char *es); | |
| int get_cmd(char* buf, int nbyte); | |
| /* Read stream char and return token*/ | |
| int get_token(char** sbuf, char* ebuf, char** stoken, char** etoken); | |
| /* Parse function */ | |
| struct cmd* parse_pipe_cmd(char** sbuf, char* ebuf); | |
| struct cmd* parse_exe_cmd(char** sbuf, char* ebuf); | |
| struct cmd* parse_redir_cmd(char** sbuf, char* ebuf); | |
| /* Main loop*/ | |
| int main(int argc, char const *argv[]) | |
| { | |
| static char buf[BUF_SIZE]; | |
| int fd, r; | |
| // Read and run input commands. | |
| while (get_cmd(buf, sizeof(buf)) >= 0) { | |
| if (buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' ') { | |
| // Clumsy but will have to do for now. | |
| // Chdir has no effect on the parent if run in the child. | |
| buf[strlen(buf) - 1] = 0; // chop \n | |
| if (chdir(buf + 3) < 0) | |
| fprintf(stderr, "cannot cd %s\n", buf + 3); | |
| continue; | |
| } | |
| if (fork1() == 0) | |
| run_cmd(parse_cmd(buf)); | |
| wait(&r); | |
| } | |
| exit(0); | |
| } | |
| int run_cmd(struct cmd* cmd) | |
| { | |
| struct cmd_exe *exec; | |
| struct cmd_pipe *pipec; | |
| struct cmd_redir *redirc; | |
| int p[2], r; | |
| if (cmd == 0) | |
| exit(-1); | |
| switch (cmd->type) { | |
| case CMD_EXE: | |
| exec = (struct cmd_exe*)cmd; | |
| if (exec->argv[0] == 0) | |
| exit(0); | |
| execvp(exec->argv[0], exec->argv); | |
| printf("exe %s failed \n", exec->argv[0]); | |
| break; | |
| case CMD_PIPE: | |
| pipec = (struct cmd_pipe*)cmd; | |
| if (pipe(p) < 0) | |
| fprintf(stderr, "Pipe error\n"); | |
| if (fork1() == 0) { | |
| close(1); | |
| dup(p[1]); | |
| close(p[0]); | |
| close(p[1]); | |
| run_cmd(pipec->left); | |
| } | |
| if (fork1() == 0) { | |
| close(0); | |
| dup(p[0]); | |
| close(p[1]); | |
| close(p[0]); | |
| run_cmd(pipec->right); | |
| } | |
| close(p[1]); | |
| close(p[0]); | |
| wait(0); | |
| wait(0); | |
| break; | |
| case CMD_REDIR_OUT: | |
| case CMD_REDIR_IN: | |
| redirc = (struct cmd_redir*)cmd; | |
| close(redirc->fd); | |
| if (open(redirc->file, redirc->mode) < 0) { | |
| fprintf(stderr, "Open %s failed\n", redirc->file); | |
| exit(-1); | |
| } | |
| run_cmd(redirc->cmd); | |
| break; | |
| default: | |
| fprintf(stderr, "Unknown command type: %d\n", cmd->type); | |
| } | |
| return 0; | |
| } | |
| /* Constructor */ | |
| struct cmd* cmd_exe(void) | |
| { | |
| struct cmd_exe* cmd; | |
| cmd = (struct cmd_exe*)malloc(sizeof(struct cmd_exe)); | |
| cmd->type = CMD_EXE; | |
| return (struct cmd*)cmd; | |
| } | |
| struct cmd* cmd_pipe(struct cmd *left, struct cmd *right) | |
| { | |
| struct cmd_pipe *cmd; | |
| cmd = (struct cmd_pipe*)malloc(sizeof(struct cmd_pipe)); | |
| cmd->type = CMD_PIPE; | |
| cmd->left = left; | |
| cmd->right = right; | |
| return (struct cmd*)cmd; | |
| } | |
| struct cmd* cmd_redir(struct cmd *subcmd, char*file, char type) | |
| { | |
| struct cmd_redir *cmd; | |
| cmd = (struct cmd_redir*)malloc(sizeof(struct cmd_redir)); | |
| cmd->type = type; | |
| cmd->cmd = subcmd; | |
| cmd->fd = (type == CMD_REDIR_IN) ? 0 : 1; | |
| cmd->mode = (type == CMD_REDIR_IN) ? O_RDONLY : O_WRONLY | O_CREAT | O_TRUNC; | |
| cmd->file = file; | |
| return (struct cmd*)cmd; | |
| } | |
| /* Helper function */ | |
| int get_cmd(char* buf, int nbyte) | |
| { | |
| if (isatty(fileno(stdin))) | |
| fprintf(stdout, "kr_shell: "); | |
| memset(buf, 0, nbyte); | |
| fgets(buf, nbyte, stdin); | |
| if (buf[0] == 0) // EOF | |
| return -1; | |
| return 0; | |
| } | |
| int fork1(void) | |
| { | |
| int pid; | |
| pid = fork(); | |
| if (pid == -1) | |
| perror("fork"); | |
| return pid; | |
| } | |
| char* mkcopy(char *s, char *es) | |
| { | |
| int n = es - s; | |
| char *c = malloc(n + 1); | |
| assert(c); | |
| strncpy(c, s, n); | |
| c[n] = 0; | |
| return c; | |
| } | |
| char whitespace[] = " \r\t\v\n"; /* NOTE: remember ' ' character*/ | |
| char symbol[] = "<|>"; | |
| /* Read stream char and return token*/ | |
| int get_token(char** sbuf, char* ebuf, char** stoken, char** etoken) | |
| { | |
| char* s; | |
| int ret = CMD_UNKNOW; | |
| s = *sbuf; | |
| while (s < ebuf && strchr(whitespace, *s)) | |
| s++; | |
| if (stoken) *stoken = s; /*Store pointer to start of token*/ | |
| switch (*s) { | |
| case 0: | |
| break; | |
| case '|': | |
| ret = CMD_PIPE; | |
| s++; | |
| break; | |
| case '<': | |
| ret = CMD_REDIR_IN; | |
| s++; | |
| break; | |
| case '>': | |
| ret = CMD_REDIR_OUT; | |
| s++; | |
| break; | |
| default: | |
| ret = CMD_EXE; | |
| while (s < ebuf && !strchr(whitespace, *s) && !strchr(symbol, *s)) | |
| s++; | |
| break; | |
| } | |
| /*Store pointer to end of token*/ | |
| if (etoken) | |
| *etoken = s; | |
| while (s < ebuf && strchr(whitespace, *s)) | |
| s++; | |
| *sbuf = s; | |
| return ret; | |
| } | |
| int peek(char** sbuf, char* ebuf, char* token) | |
| { | |
| char *s = *sbuf; | |
| while (s < ebuf && strchr(whitespace, *s)) | |
| s++; | |
| *sbuf = s; | |
| return (*s && strchr(token, *s)); | |
| } | |
| /* Parse input to cmds*/ | |
| struct cmd* parse_cmd(char* buf) | |
| { | |
| struct cmd *cmd; | |
| char* ebuf = buf + strlen(buf); | |
| cmd = parse_pipe_cmd(&buf, ebuf); | |
| peek(&buf, ebuf, ""); | |
| if (buf != ebuf) { | |
| fprintf(stderr, "lefovers %s\n", buf); | |
| } | |
| return cmd; | |
| } | |
| /* Parse a pipe command*/ | |
| struct cmd* parse_pipe_cmd(char** sbuf, char* ebuf) | |
| { | |
| struct cmd *cmd; | |
| cmd = parse_redir_cmd(sbuf, ebuf); | |
| if (peek(sbuf, ebuf, "|")) { | |
| get_token(sbuf, ebuf, 0, 0); | |
| cmd = cmd_pipe(cmd, parse_redir_cmd(sbuf, ebuf)); | |
| } | |
| return cmd; | |
| } | |
| /* Parse a pipe command*/ | |
| struct cmd* parse_redir_cmd(char** sbuf, char* ebuf) | |
| { | |
| int tok; | |
| char *q, *eq; | |
| struct cmd* cmd; | |
| cmd = parse_exe_cmd(sbuf, ebuf); | |
| if (peek(sbuf, ebuf, "<>")) { | |
| tok = get_token(sbuf, ebuf, 0, 0); | |
| if (get_token(sbuf, ebuf, &q, &eq) != CMD_EXE) { | |
| fprintf(stderr, "Missing file for redirect\n"); | |
| exit(-1); | |
| } | |
| cmd = cmd_redir(cmd, mkcopy(q, eq), tok); | |
| } | |
| return cmd; | |
| } | |
| /* Parse a exec command*/ | |
| struct cmd* parse_exe_cmd(char** sbuf, char* ebuf) | |
| { | |
| char *q, *eq; | |
| int tok, argc; | |
| struct cmd_exe *cmd; | |
| struct cmd *ret; | |
| ret = cmd_exe(); | |
| cmd = (struct cmd_exe*)ret; | |
| argc = 0; | |
| while (!peek(sbuf, ebuf, ">|<")) { | |
| if ((tok = get_token(sbuf, ebuf, &q, &eq)) == 0) | |
| break; | |
| if (tok != CMD_EXE) { | |
| fprintf(stderr, "syntax error\n"); | |
| exit(-1); | |
| } | |
| cmd->argv[argc] = mkcopy(q, eq); | |
| argc++; | |
| if (argc >= MAXARGS) { | |
| fprintf(stderr, "too many args\n"); | |
| exit(-1); | |
| } | |
| } | |
| cmd->argv[argc] = 0; | |
| return ret; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * @Author: Trung Kien | |
| * @Date: 2017-03-25 11:35:58 | |
| * @Last Modified by: ksvbka | |
| * @Last Modified time: 2017-03-25 14:51:06 | |
| */ | |
| #include <stdlib.h> | |
| #include <unistd.h> // for syscall | |
| #include <stdio.h> | |
| #include <fcntl.h> //File control option - manipulate file descriptor | |
| #include <string.h> | |
| #include <assert.h> | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include <sys/wait.h> | |
| // Simplifed xv6 shell. | |
| #define MAXARGS 10 | |
| #define BUF_SIZE 20 | |
| #define CMD_UNKNOW 0x00 | |
| #define CMD_EXE 0x01 | |
| #define CMD_PIPE 0x02 | |
| #define CMD_REDIR_OUT 0x04 | |
| #define CMD_REDIR_IN 0x08 | |
| /* Generic cmd */ | |
| struct cmd { | |
| char type; | |
| }; | |
| /* Execution cmd */ | |
| struct cmd_exe { | |
| char type; /* CMD_EXE*/ | |
| char* argv[MAXARGS]; /* All argument of exec*/ | |
| }; | |
| /* Pipe cmd*/ | |
| struct cmd_pipe { | |
| char type; /* CMD_PIPE*/ | |
| struct cmd *left; /* CMD after '|' symbol */ | |
| struct cmd *right; /* CMD before '|' symbol */ | |
| }; | |
| /* redirect cmd*/ | |
| struct cmd_redir { | |
| int type; /* < or >*/ | |
| struct cmd *cmd; /* the command to be run (e.g., an execcmd)*/ | |
| char *file; /* the input/output file */ | |
| int mode; /* the mode to open the file with*/ | |
| int fd; /* the file descriptor number to use for the file */ | |
| }; | |
| /* Get cmd to a buf*/ | |
| int get_cmd(char* buf, int nbyte); | |
| /* Parse input to cmds*/ | |
| struct cmd* parse_cmd(char* buf); | |
| /* Function execution cmd*/ | |
| int run_cmd(struct cmd* cmd); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment