csapp-lab5 shell-lab
来源:互联网 发布:国产数据库怎么样 编辑:程序博客网 时间:2024/05/21 10:40
/* * tsh - A tiny shell program with job control * * <Put your name and login ID here> */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <ctype.h>#include <signal.h>#include <sys/types.h>#include <sys/wait.h>#include <errno.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 *//* Job states */#define UNDEF 0 /* undefined */#define FG 1 /* running in foreground */#define BG 2 /* running in background */#define ST 3 /* stopped *//* * 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[] = "tsh> "; /* command line prompt (DO NOT CHANGE) */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);void do_bgfg(char **argv);void waitfg(pid_t pid);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 paseArgument(int *isJob, const char *pj_char);int parseline(const char *cmdline, char **argv); 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);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);/* Here are error-handling wrapper functions */void Sigemptyset(sigset_t *mask);void Sigaddset(sigset_t *mask, int sign);void Sigprocmask(int how, sigset_t *mask,sigset_t *oldmask);void Setpgid(pid_t pid,pid_t gpid);pid_t Fork(void);// void Execve(const char *filename, char *const argv[], char *const envp[]);void Kill(pid_t pid,int sig);/* * 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 */ /* These are the ones you will need to implement */ Signal(SIGINT, sigint_handler); /* ctrl-c */ Signal(SIGTSTP, sigtstp_handler); /* ctrl-z */ Signal(SIGCHLD, sigchld_handler); /* Terminated or stopped child */ /* This one provides a clean way to kill the shell */ Signal(SIGQUIT, sigquit_handler); /* Initialize the job list */ initjobs(jobs); /* Execute the shell's read/eval loop */ while (1) { /* Read command line */ if (emit_prompt) { 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(stdout); } 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]; /* Argument list execve() */ char buf[MAXLINE]; /* Holds modified command line */ int bg; /* Should the job run in bg or fg */ pid_t pid; /* process id */ sigset_t mask; strcpy(buf, cmdline); bg = parseline(buf, argv); if (argv[0] == NULL) { return; } if (!builtin_cmd(argv)) { Sigemptyset(&mask); Sigaddset(&mask, SIGCHLD); Sigprocmask(SIG_BLOCK, &mask, NULL); if ((pid = Fork()) == 0) { Sigprocmask(SIG_UNBLOCK, &mask, NULL); Setpgid(0, 0); if (execve(argv[0], argv, environ) < 0) { printf("%s: Command not found\n", argv[0]); exit(0); } } // 必须在父进程添加job以后才能取消屏蔽信号 addjob(jobs, pid, bg ? BG : FG, cmdline); Sigprocmask(SIG_UNBLOCK, &mask, NULL); // 根据是否是后台job决定是否等待子进程完成 if (!bg) { waitfg(pid); } else { printf("[%d] (%d) %s", pid2jid(pid), pid, cmdline); } } return;}/* * parseline - Parse the command line and build the argv array. * * Characters enclosed in single quotes are treated as a single * argument. Return true 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; /* points to first space delimiter */ int argc; /* number of args */ int bg; /* background job? */ 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; if (*buf == '\'') { buf++; delim = strchr(buf, '\''); } else { delim = strchr(buf, ' '); } while (delim) { argv[argc++] = buf; *delim = '\0'; buf = delim + 1; while (*buf && (*buf == ' ')) /* ignore spaces */ buf++; if (*buf == '\'') { buf++; delim = strchr(buf, '\''); } else { delim = 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;}/* * builtin_cmd - If the user has typed a built-in command then execute * it immediately. */int builtin_cmd(char **argv) { if (!strcmp(argv[0], "quit")) exit(0); if (!strcmp(argv[0], "&")) return 1; if (!strcmp(argv[0], "fg") || !strcmp(argv[0], "bg")) { do_bgfg(argv); return 1; } if (!strcmp(argv[0], "jobs")) { listjobs(jobs); return 1; } return 0; /* not a builtin command */}/* * do_bgfg - Execute the builtin bg and fg commands * 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. * The bg(fg)<job> command restarts <job> by sending it a SIGCONT signal, * and then runs it in the background(background). The <job> argument * can be either a PID or a JID. * * Each job can be identified by either a process ID (PID) or a job ID * (JID), which is a positive integer assigned by tsh. JIDs should be * denoted on the command line by the prefix ’%’. * * For example, “%5” denotes JID 5, and “5” denotes PID 5. */void do_bgfg(char **argv) { char* pj_char = argv[1]; int JIDorPID, number; int bg = !strcmp(argv[0], "bg"); if (argv[1] == NULL) { printf("%s command requires PID or %%jobid argument\n", (bg?"bg":"fg")); return; } number = paseArgument(&JIDorPID, pj_char); if (number < 0) { printf("%s: argument must be a PID or %%jobid\n", (bg?"bg":"fg")); return; } if (JIDorPID == 1) { if (number > maxjid(jobs)) { printf("%%%d: No such job\n", number); return; } struct job_t *job = getjobjid(jobs, number); if ((job == NULL) || job->state == UNDEF) { printf("%%%d: No such job\n", number); return; } else if (bg && (job->state == ST)) { job->state = BG; Kill(-(job->pid), SIGCONT); printf("[%d] (%d) %s", number, job->pid, job->cmdline); } else if (!bg && (job->state == ST || job->state == BG)) { job->state = FG; Kill(-number, SIGCONT); waitfg(job->pid); } } else if (JIDorPID == 2) { struct job_t *job = getjobpid(jobs, number); if ((job == NULL) || job->state == UNDEF) { printf("(%d): No such process\n", number); return; } else if (bg && (job->state == ST)) { job->state = BG; Kill(-number, SIGCONT); printf("[%d] (%d) %s", job->jid, number, job->cmdline); } else if (!bg && (job->state == ST || job->state == BG)) { job->state = FG; Kill(-number, SIGCONT); waitfg(job->pid); } } return;}/* * parse arguments to fg/bg * argument: JIDorPID * %JID -> JIDorPID = 1 * %PID -> JIDorPID = 2 * return: number * 0 -> not a valid number input * positive number -> valid */int paseArgument(int *JIDorPID, const char *pj_char){ int number; if (pj_char[0] == '%') { number = atoi(pj_char + 1); if (number == 0) return -1; *JIDorPID = 1; } else { number = atoi(pj_char); // printf("pid number = %d\n", number); if (number == 0) return -1; *JIDorPID = 2; } return number;}/* * waitfg - Block until process pid is no longer the foreground process */void waitfg(pid_t pid){ while (pid == fgpid(jobs)) { sleep(0); } return;}/***************** * Signal handlers *****************//* * sigchld_handler - The kernel sends a SIGCHLD to the shell whenever * a child job terminates (becomes a zombie), or stops because it * received a SIGSTOP or SIGTSTP signal. The handler reaps all * available zombie children, but doesn't wait for any other * currently running children to terminate. */void sigchld_handler(int sig) { int status; pid_t pid; while ((pid = waitpid(-1, &status, (WNOHANG|WUNTRACED))) > 0) { // 子进程正常终止 if (WIFEXITED(status)) { deletejob(jobs, pid); } // 子进程接受了一个未捕获的信号导致terminate if (WIFSIGNALED(status)) { printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(pid), pid, WTERMSIG(status)); deletejob(jobs, pid); } // 子进程当前处于stop状态 if (WIFSTOPPED(status)) { printf("Job [%d] (%d) stopped by signal %d\n", pid2jid(pid), pid, WSTOPSIG(status)); struct job_t *job = getjobpid(jobs, pid); if (job != NULL) { job->state = ST; } } } if (errno != ECHILD) unix_error("waitpid error"); return;}/* * sigint_handler - The kernel sends a SIGINT to the shell whenver the * user types ctrl-c at the keyboard. Catch it and send it along * to the foreground job. */void sigint_handler(int sig) { pid_t pid = fgpid(jobs); /* 获取当前的前台job pid*/ if (pid != 0) { Kill(-pid, SIGINT); } return;}/* * sigtstp_handler - The kernel sends a SIGTSTP to the shell whenever * the user types ctrl-z at the keyboard. Catch it and suspend the * foreground job by sending it a SIGTSTP. */void sigtstp_handler(int sig) { pid_t pid = fgpid(jobs); if (pid != 0) { struct job_t *job = getjobpid(jobs, pid); if (job->state == ST) { /* 已经处于stop的job不需要发送信号了 */ return; } else { Kill(-pid, SIGTSTP); } } return;}/********************* * End signal handlers *********************//*********************************************** * Helper routines that manipulate the job list **********************************************//* clearjob - Clear the entries in a job struct */void clearjob(struct job_t *job) { job->pid = 0; job->jid = 0; job->state = UNDEF; job->cmdline[0] = '\0';}/* initjobs - Initialize the job list */void initjobs(struct job_t *jobs) { int i; for (i = 0; i < MAXJOBS; i++) clearjob(&jobs[i]);}/* maxjid - Returns largest allocated job ID */int maxjid(struct job_t *jobs) { int i, max=0; for (i = 0; i < MAXJOBS; i++) if (jobs[i].jid > max) max = jobs[i].jid; return max;}/* addjob - Add a job to the job list */int addjob(struct job_t *jobs, pid_t pid, int state, char *cmdline) { int i; if (pid < 1) return 0; for (i = 0; i < MAXJOBS; i++) { if (jobs[i].pid == 0) { jobs[i].pid = pid; jobs[i].state = state; jobs[i].jid = nextjid++; if (nextjid > MAXJOBS) nextjid = 1; strcpy(jobs[i].cmdline, cmdline); if(verbose){ printf("Added job [%d] %d %s\n", jobs[i].jid, jobs[i].pid, jobs[i].cmdline); } return 1; } } printf("Tried to create too many jobs\n"); return 0;}/* deletejob - Delete a job whose PID=pid from the job list */int deletejob(struct job_t *jobs, pid_t pid) { int i; if (pid < 1) return 0; for (i = 0; i < MAXJOBS; i++) { if (jobs[i].pid == pid) { clearjob(&jobs[i]); nextjid = maxjid(jobs)+1; return 1; } } return 0;}/* fgpid - Return PID of current foreground job, 0 if no such job */pid_t fgpid(struct job_t *jobs) { int i; for (i = 0; i < MAXJOBS; i++) if (jobs[i].state == FG) return jobs[i].pid; return 0;}/* getjobpid - Find a job (by PID) on the job list */struct job_t *getjobpid(struct job_t *jobs, pid_t pid) { int i; if (pid < 1) return NULL; for (i = 0; i < MAXJOBS; i++) if (jobs[i].pid == pid) return &jobs[i]; return NULL;}/* getjobjid - Find a job (by JID) on the job list */struct job_t *getjobjid(struct job_t *jobs, int jid) { int i; if (jid < 1) return NULL; for (i = 0; i < MAXJOBS; i++) if (jobs[i].jid == jid) return &jobs[i]; return NULL;}/* pid2jid - Map process ID to job ID */int pid2jid(pid_t pid) { int i; if (pid < 1) return 0; for (i = 0; i < MAXJOBS; i++) if (jobs[i].pid == pid) { return jobs[i].jid; } return 0;}/* listjobs - Print the job list */void listjobs(struct job_t *jobs) { int i; for (i = 0; i < MAXJOBS; i++) { if (jobs[i].pid != 0) { printf("[%d] (%d) ", jobs[i].jid, jobs[i].pid); switch (jobs[i].state) { case BG: printf("Running "); break; case FG: printf("Foreground "); break; case ST: printf("Stopped "); break; default: printf("listjobs: Internal error: job[%d].state=%d ", i, jobs[i].state); } printf("%s", jobs[i].cmdline); } }}/****************************** * end job list helper routines ******************************//*********************** * Other helper routines ***********************//* * usage - print a help message */void usage(void) { printf("Usage: shell [-hvp]\n"); printf(" -h print this message\n"); printf(" -v print additional diagnostic information\n"); printf(" -p do not emit a command prompt\n"); exit(1);}/* * unix_error - unix-style error routine */void unix_error(char *msg){ fprintf(stdout, "%s: %s\n", msg, strerror(errno)); exit(1);}/* * app_error - application-style error routine */void app_error(char *msg){ fprintf(stdout, "%s\n", msg); exit(1);}/* * Signal - wrapper for the sigaction function */handler_t *Signal(int signum, handler_t *handler) { struct sigaction action, old_action; action.sa_handler = handler; sigemptyset(&action.sa_mask); /* block sigs of type being handled */ action.sa_flags = SA_RESTART; /* restart syscalls if possible */ if (sigaction(signum, &action, &old_action) < 0) unix_error("Signal error"); return (old_action.sa_handler);}/* * sigquit_handler - The driver program can gracefully terminate the * child shell by sending it a SIGQUIT signal. */void sigquit_handler(int sig) { printf("Terminating after receipt of SIGQUIT signal\n"); exit(1);}void Sigprocmask(int how, sigset_t *set, sigset_t *oldset){ if (sigprocmask(how, set, oldset) < 0) unix_error("Sigprocmask error"); return;}void Sigemptyset(sigset_t *set){ if (sigemptyset(set) < 0) unix_error("Sigemptyset error"); return;}void Sigaddset(sigset_t *set, int signum){ if (sigaddset(set, signum) < 0) unix_error("Sigaddset error"); return;}void Setpgid(pid_t pid, pid_t pgid) { if (setpgid(pid, pgid) < 0) { unix_error("eval: setpgid failed.\n"); }}pid_t Fork(void) { pid_t pid; if ((pid = fork()) < 0) unix_error("Fork error"); return pid;}void Kill(pid_t pid, int signum) { int rc; if ((rc = kill(pid, signum)) < 0) unix_error("Kill error");}
阅读全文
0 0
- csapp-lab5 shell-lab
- CSAPP: shell lab
- CSAPP: Shell Lab
- CSAPP shell-lab
- 【CSAPP】Shell Lab 外壳实验
- <csapp> malloc lab (《深入理解计算机系统》lab6) (附lab4\lab5下载地址)
- CSAPP LAB---Proxy lab
- CSAPP 六个重要实验 lab5
- CSAPP Lab5--Writing a Dynamic Storage Allocator
- CSAPP: bomb lab
- CSAPP: buffer lab
- CSAPP: malloc lab
- CSAPP LAB---MALLOC实验
- CSAPP LAB---shlab-handout
- 【CSAPP】malloc Lab
- CSAPP Data Lab
- CSAPP: Malloc Lab 7
- CSAPP: Buffer Lab
- 《剑指offer》学习笔记
- 深度学习用到的代价函数------交叉熵
- linux的sh脚本编程
- 【Scikit-Learn 中文文档】高斯过程
- ICPC2017香港赛区游记
- csapp-lab5 shell-lab
- Sql server 使用全局触发器限制IP 实现白名单功能
- 【Scikit-Learn 中文文档】交叉分解
- Codeforces Round #447 (Div. 2) B. Ralph And His Magic Field 推规律+证明
- js中的parseInt()
- 备忘录模式
- 饮水机和水桶图解RAID方式,强烈推荐
- 简单的打印素数、打印乘法口诀表和判断闰年
- jzoj 3420 最优配对问题