/* * builtin_cmd - If the user has typed a built-in command then execute * it immediately. */ intbuiltin_cmd(char **argv) { if (!strcmp(argv[0], "quit")) // quit exit(0); if (!strcmp(argv[0], "jobs")) // jobs { listjobs(jobs); return1; }
if (!strcmp(argv[0], "echo")) // echo { printf("%s\n", argv[1]); return1; }
if(!strcmp(argv[0], "bg") || !strcmp(argv[0], "fg")) // bg or fg { do_bgfg(argv); return1; } return0; /* not a builtin command */ }
/* * 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. */ voideval(char *cmdline) { char *argv[MAXARGS]; char buf[MAXLINE]; int bg; pid_t pid; sigset_t mask;
/* * 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. */ voidsigint_handler(int sig) { pid_t pid = fgpid(jobs); int jid = pid2jid(pid); if (pid != 0) { if (kill(-pid, SIGKILL) < 0) // kill pid { unix_error("error when kill in sigint_handler"); return; } printf("Job [%d] (%d) terminated by signal %d\n", jid, pid, sig); deletejob(jobs, pid); } 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. */ voidsigtstp_handler(int sig) { int pid = fgpid(jobs); int jid = pid2jid(pid); if (pid != 0) { printf("Job [%d] (%d) Stopped by signal %d\n", jid, pid, sig); getjobpid(jobs, pid)->state = ST; kill(-pid, SIGTSTP); } return; }
/* * 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. */ voidsigchld_handler(int sig) { int status; pid_t pid; // Waiting for handling all of the child processes according to their status while ((pid = waitpid(fgpid(jobs), &status, WNOHANG|WUNTRACED)) > 0) { if (WIFSTOPPED(status)){ getjobpid(jobs, pid)->state = ST; printf("[%d] Stopped %s\n", pid2jid(pid), jobs->cmdline); } elseif (WIFSIGNALED(status)){ printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(pid), pid, WTERMSIG(status)); deletejob(jobs,pid); } elseif (WIFEXITED(status)){ deletejob(jobs, pid); } } if (errno != ECHILD) { unix_error("waitpid error"); } return; }