Skip to content

Instantly share code, notes, and snippets.

@ksvbka
Created March 25, 2017 09:26
Show Gist options
  • Select an option

  • Save ksvbka/08ac9ccdd21b4a5c38d70c53b8d59fd1 to your computer and use it in GitHub Desktop.

Select an option

Save ksvbka/08ac9ccdd21b4a5c38d70c53b8d59fd1 to your computer and use it in GitHub Desktop.
Simple shell
/*
* @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;
}
/*
* @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