📄 tsh.c
字号:
/* * tsh - A tiny shell program with job control * * <Put your name and login ID here> *----------------- <Name : liang rongtang> ------------------ *----------------- <ID :0472528 > ------------------ */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <ctype.h>#include <signal.h>#include <sys/types.h>#include <fcntl.h>#include <sys/wait.h>#include <errno.h>#include <sys/dir.h>/* Misc manifest constants */#define MAXLINE 1024 /* max line size */#define MAXARGS 128 /* max args on a command line */#define MAXJOBS 16 /* max jobs at any point in time */#define MAXJID 1<<16 /* max job ID */#define MAX_CMD_BUF 50#define MAX_CMD_LEN 30#define MAX_ARG_LEN 30/* Job states */#define UNDEF 0 /* undefined */#define FG 1 /* running in foreground */#define BG 2 /* running in background */#define ST 3 /* stopped *//*Cmd struct*/struct cmd_struct{ char *name; char *cmd_manner;/*The instruction will execute following the cmd_manner*/};/* * Jobs states: FG (foreground), BG (background), ST (stopped) * Job state transitions and enabling actions: * FG -> ST : ctrl-z * ST -> FG : fg command * ST -> BG : bg command * BG -> FG : fg command * At most 1 job can be in the FG state. *//* Global variables */extern char **environ; /* defined in libc */char prompt[128]; /* command line prompt */int verbose = 0; /* if true, print additional output */int nextjid = 1; /* next job ID to allocate */char sbuf[MAXLINE]; /* for composing sprintf messages */struct job_t { /* The job struct */ pid_t pid; /* job PID */ int jid; /* job ID [1, 2, ...] */ int state; /* UNDEF, BG, FG, or ST */ char cmdline[MAXLINE]; /* command line */};struct job_t jobs[MAXJOBS]; /* The job list *//* End global variables *//* Function prototypes *//* Here are the functions that you will implement */void eval(char *cmdline);int builtin_cmd(char **argv, int *input_fd, int *output_fd);void do_bgfg(char **argv, int output_fd);void waitfg(pid_t pid, int output_fd);void execute_cd(char **argv);void makedir(char **argv);void removedir(char **argv);void sigchld_handler(int sig);void sigtstp_handler(int sig);void sigint_handler(int sig);/* Here are helper routines that we've provided for you */int parseline(const char *cmdline, char **argv);char *firstTok(const char *space, const char *input, const char *output, const char *pipe);void sigquit_handler(int sig);void clearjob(struct job_t *job);void initjobs(struct job_t *jobs);int maxjid(struct job_t *jobs); int addjob(struct job_t *jobs, pid_t pid, int state, char *cmdline);int deletejob(struct job_t *jobs, pid_t pid); pid_t fgpid(struct job_t *jobs);struct job_t *getjobpid(struct job_t *jobs, pid_t pid);struct job_t *getjobjid(struct job_t *jobs, int jid); int pid2jid(pid_t pid); void listjobs(struct job_t *jobs, int output_fd);void usage(void);void unix_error(char *msg);void app_error(char *msg);typedef void handler_t(int);handler_t *Signal(int signum, handler_t *handler);/* * main - The shell's main routine */int main(int argc, char **argv) { char c; char cmdline[MAXLINE]; int emit_prompt = 1; /* emit prompt (default) */ /* Redirect stderr to stdout (so that driver will get all output * on the pipe connected to stdout) */ dup2(1, 2); /* Parse the command line */ while ((c = getopt(argc, argv, "hvp")) != EOF) { switch (c) { case 'h': /* print help message */ usage(); break; case 'v': /* emit additional diagnostic info */ verbose = 1; break; case 'p': /* don't print a prompt */ emit_prompt = 0; /* handy for automatic testing */ break; default: usage(); } } /* Install the signal handlers */ Signal(SIGINT, sigint_handler); /* ctrl-c */ Signal(SIGTSTP, sigtstp_handler); /* ctrl-z */ Signal(SIGCHLD, sigchld_handler); /* terminated or stopped child */ Signal(SIGQUIT, sigquit_handler); /* so parent can cleanly terminate child*/ /* Initialize the job list */ initjobs(jobs); /* Execute the shell's read/eval loop */ while (1) { /* Read command line */ if (emit_prompt) { getcwd(prompt,128); printf("%s>", prompt); fflush(stdout); } if ((fgets(cmdline, MAXLINE, stdin) == NULL) && ferror(stdin)) app_error("fgets error"); if (feof(stdin)) { /* End of file (ctrl-d) */ fflush(stdout); exit(0); } /* Evaluate the command line */ eval(cmdline); fflush(stdout); fflush(stderr); } exit(0); /* control never reaches here */}/* * eval - Evaluate the command line that the user has just typed in * * If the user has requested a built-in command (quit, jobs, bg or fg) * then execute it immediately. Otherwise, fork a child process and * run the job in the context of the child. If the job is running in * the foreground, wait for it to terminate and then return. Note: * each child process must have a unique process group ID so that our * background children don't receive SIGINT (SIGTSTP) from the kernel * when we type ctrl-c (ctrl-z) at the keyboard. */void eval(char *cmdline) { char *argv[MAXARGS]; int bg; /*should the job run in bg or fg*/ pid_t pid; sigset_t mask; int in = STDIN_FILENO; int out = STDOUT_FILENO; int *input_fd = ∈ int *output_fd=&out; int input=0; int output=0; int argc=0; bg=parseline(cmdline,argv) ; if (argv[0]==NULL) return; /*ignore empty line*/ while(argv[argc] !=NULL&&*argv[argc] !='\0') { if(*argv[argc]=='<') /*is there input I\O redirection*/ { if(in!=STDIN_FILENO) /*illegal to use multiple redirection*/ { printf("Error: Ambiguous I/O redirection\n"); return; } else { in=open(argv[argc+1],O_RDONLY); /*open the specific file*/ if(in==-1) { printf("Error: %s No such file or directory\n",argv[argc+1]); return; } else input=1; } } if(*argv[argc]=='>') /*is there output I\O redirection*/ { if(out!=STDOUT_FILENO) /*illegal to use multiple redirection*/ { printf("Error: Ambiguous I/O redirection\n"); return; } else { out=open(argv[argc+1],O_WRONLY|O_CREAT); /*open the specific file*/ output=1; } argv[argc]=NULL; } argc++; } if(!builtin_cmd(argv,input_fd,output_fd)) /*if the command a built-in command*/ { sigemptyset(&mask); sigaddset(&mask,SIGCHLD); sigprocmask(SIG_BLOCK,&mask,NULL); /*block signal SIGCHLD*/ if((pid=fork())==0) { sigprocmask(SIG_UNBLOCK,&mask,NULL); /*unblock signal SIGCHLD*/ setpgid(0,0); /*pid is set for the job id*/ if(input==1) { dup2(in,STDIN_FILENO); /*job should read file from in instead of STDIN*/ } if(output==1) { dup2(out,STDOUT_FILENO); /*job should write to out in instead of STDOUT*/ } if(execve(argv[0],argv,environ)<0 ) { printf("%s:Command not found.\n",argv[0]); exit(0); } } addjob(jobs,pid,bg+1,cmdline); /*add job to joblist*/ sigprocmask(SIG_UNBLOCK,&mask,NULL); /*unblock signal SIGCHLD*/ if(!bg) /*run in foreground*/ { waitfg(pid ,*output_fd); /*wait for foreground job to terminate*/ } else /*run in background*/ { printf("[%d] (%d) %s",pid2jid(pid),pid,cmdline); } } return;}/* * parseline - Parse the command line and build the argv array. * Return true (1) if the user has requested a BG job, false * if the user has requested a FG job. */int parseline(const char *cmdline, char **argv) { static char array[MAXLINE]; /* holds local copy of command line */ char *buf = array; /* ptr that traverses command line */ char *delim_space; /* points to first space delimiter */ char *delim_in; /* points to the first < delimiter */ char *delim_out; /* points to the first > delimiter */ char *delim_pipe; /* points to the first | delimiter */ char *delim; /* points to the first delimiter */ int argc; /* number of args */ int bg; /* background job? */ char *last_space = NULL; /* The address of the last space */ strcpy(buf, cmdline); buf[strlen(buf)-1] = ' '; /* replace trailing '\n' with space */ while (*buf && (*buf == ' ')) /* ignore leading spaces */ buf++; /* Build the argv list */ argc = 0; delim_space = strchr(buf, ' '); delim_in = strchr(buf, '<'); delim_out = strchr(buf, '>'); delim_pipe = strchr(buf, '|'); while ((delim = firstTok(delim_space, delim_in, delim_out, delim_pipe))) { if(delim == delim_space) { argv[argc++] = buf; *delim = '\0'; last_space = delim; } else if(delim == delim_in) { if((last_space && last_space != (delim - 1)) || (!last_space)) { argv[argc++] = buf; *delim = '\0'; } argv[argc++] = "<"; last_space = 0; } else if(delim == delim_out) { if((last_space && last_space != (delim - 1)) || (!last_space)) { argv[argc++] = buf; *delim = '\0'; } argv[argc++] = ">"; last_space = 0; } else if(delim == delim_pipe) { if((last_space && last_space != (delim - 1)) || (!last_space)) { argv[argc++] = buf; *delim = '\0'; } argv[argc++] = "|"; last_space = 0; } buf = delim + 1; while (*buf && (*buf == ' ')) /* ignore spaces */ buf++; delim_space = strchr(buf, ' '); delim_in = strchr(buf, '<'); delim_out = strchr(buf, '>'); delim_pipe = strchr(buf, '|'); } argv[argc] = NULL; if (argc == 0) /* ignore blank line */ return 1; /* should the job run in the background? */ if ((bg = (*argv[argc-1] == '&')) != 0) argv[--argc] = NULL; return bg;}/* * firstTok - Returns a pointer to the first (lowest addy) of the four pointers * that isn't NULL. */char *firstTok(const char *space, const char *input, const char *output, const char *pipe) { const char *possible[4]; unsigned int min; int i = 1, n = 0; if(space == NULL && input == NULL && output == NULL && pipe == NULL) return NULL; if(space != NULL) { possible[n++] = space; } if(input != NULL) { possible[n++] = input; } if(output != NULL) { possible[n++] = output; } if(pipe != NULL) { possible[n++] = pipe; } min = (unsigned)possible[0]; for(;i<n;i++) { if(((unsigned)possible[i]) < min) min = (unsigned)possible[i]; } return (char *)min;}/* * builtin_cmd - If the user has typed a built-in command then execute * it immediately. */int builtin_cmd(char **argv, int *input_fd, int *output_fd) { if(!strcmp(argv[0],"exit")) /*exit command, exit directly*/ exit(0); if(!strcmp(argv[0],"cd")){ execute_cd(argv); return 1; } if(!strcmp(argv[0],"mkdir")){ makedir(argv); return 1; } if(!strcmp(argv[0],"rmdir")){ removedir(argv); return 1; } if(!strcmp(argv[0],"&")) return 1; if(!strcmp(argv[0],"jobs")) /*jobs command ,list all jobs*/ { listjobs(jobs,*output_fd); return 1; } if((!strcmp(argv[0],"bg"))||(!strcmp(argv[0],"fg"))) /*bg\fg command */ { do_bgfg(argv,*output_fd); return 1; } return 0; /* not a builtin command */}/**execute_cd - Execute the cd command
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -