Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * tsh - A tiny shell program with job control
- * <The line above is not a sufficient documentation.
- * You will need to write your program documentation.
- * Follow the 15-213/18-213/15-513 style guide at
- * http://www.cs.cmu.edu/~213/codeStyle.html.>
- *
- * @Date October 24 2016
- * @Author Sachin Menezes <smenezes>
- */
- #include <sys/wait.h>
- #include "tsh_helper.h"
- #include "csapp.h"
- /*
- * If DEBUG is defined, enable contracts and printing on dbg_printf.
- */
- #ifdef DEBUG
- /* When debugging is enabled, these form aliases to useful functions */
- #define dbg_printf(...) printf(__VA_ARGS__)
- #define dbg_requires(...) assert(__VA_ARGS__)
- #define dbg_assert(...) assert(__VA_ARGS__)
- #define dbg_ensures(...) assert(__VA_ARGS__)
- #else
- /* When debugging is disabled, no code gets generated for these */
- #define dbg_printf(...)
- #define dbg_requires(...)
- #define dbg_assert(...)
- #define dbg_ensures(...)
- #endif
- volatile sig_atomic_t flag;
- /* Function prototypes */
- void eval(const char *cmdline);
- void sigchld_handler(int sig);
- void sigtstp_handler(int sig);
- void sigint_handler(int sig);
- void sigquit_handler(int sig);
- void execute_builtin_command(builtin_state builtin);
- /*
- * <Write main's function header documentation. What does main do?>
- * "Each function should be prefaced with a comment describing the purpose
- * of the function (in a sentence or two), the function's arguments and
- * return value, any error cases that are relevant to the caller,
- * any pertinent side effects, and any assumptions that the function makes."
- */
- int main(int argc, char **argv)
- {
- char c;
- char cmdline[MAXLINE_TSH]; // Cmdline for fgets
- bool emit_prompt = true; // Emit prompt (default)
- // Redirect stderr to stdout (so that driver will get all output
- // on the pipe connected to stdout)
- Dup2(STDOUT_FILENO, STDERR_FILENO);
- // Parse the command line
- while ((c = getopt(argc, argv, "hvp")) != EOF)
- {
- switch (c)
- {
- case 'h': // Prints help message
- usage();
- break;
- case 'v': // Emits additional diagnostic info
- verbose = true;
- break;
- case 'p': // Disables prompt printing
- emit_prompt = false;
- break;
- default:
- usage();
- }
- }
- // Install the signal handlers
- Signal(SIGINT, sigint_handler); // Handles ctrl-c
- Signal(SIGTSTP, sigtstp_handler); // Handles ctrl-z
- Signal(SIGCHLD, sigchld_handler); // Handles terminated or stopped child
- Signal(SIGTTIN, SIG_IGN);
- Signal(SIGTTOU, SIG_IGN);
- Signal(SIGQUIT, sigquit_handler);
- // Initialize the job list
- initjobs(job_list);
- // Execute the shell's read/eval loop
- while (true)
- {
- if (emit_prompt)
- {
- printf("%s", prompt);
- fflush(stdout);
- }
- if ((fgets(cmdline, MAXLINE_TSH, stdin) == NULL) && ferror(stdin))
- {
- app_error("fgets error");
- }
- if (feof(stdin))
- {
- // End of file (ctrl-d)
- printf ("\n");
- fflush(stdout);
- fflush(stderr);
- return 0;
- }
- // Remove the trailing newline
- cmdline[strlen(cmdline)-1] = '\0';
- // Evaluate the command line
- eval(cmdline);
- fflush(stdout);
- }
- return -1; // control never reaches here
- }
- /* Handy guide for eval:
- *
- * 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.
- */
- /*
- * <What does eval do?>
- */
- void Execve_sachin(const char *filename, char *const argv[], char *const envp[])
- {
- if (execve(filename, argv, envp) < 0)
- printf("%s: Command not found. \n", argv[0]);
- }
- job_state get_job_state(parseline_return parse_result) {
- if (parse_result == PARSELINE_BG)
- return BG;
- return FG;
- }
- void print_bg_job(int pid) {
- sigset_t mask_all, prev_one;
- Sigfillset(&mask_all);
- Sigprocmask(SIG_BLOCK, &mask_all, &prev_one);
- struct job_t *job = getjobpid(job_list, pid);
- Sigprocmask(SIG_SETMASK, &prev_one, NULL);
- printf("[%d] (%d) %s\n", job->jid, job->pid, job->cmdline);
- }
- void execute_builtin_command(builtin_state builtin) {
- if (builtin == BUILTIN_QUIT) {
- exit(0);
- }
- }
- void eval(const char *cmdline)
- {
- parseline_return parse_result;
- struct cmdline_tokens token;
- pid_t pid;
- sigset_t mask_all, prev_one, mask_one, empty_set;
- // Parse command line
- parse_result = parseline(cmdline, &token);
- if (parse_result == PARSELINE_ERROR || parse_result == PARSELINE_EMPTY)
- {
- return;
- }
- if (token.builtin != BUILTIN_NONE) {
- execute_builtin_command(token.builtin);
- return;
- }
- job_state state = get_job_state(parse_result);
- Sigfillset(&mask_all);
- Sigemptyset(&mask_one);
- Sigemptyset(&empty_set);
- Sigaddset(&mask_one, SIGCHLD);
- Sigprocmask(SIG_BLOCK, &mask_all, &prev_one); // Blocking SIGCHLD
- if ((pid = Fork()) == 0) {
- setpgid(0,0); // Each child process should belong to a different process group
- Sigprocmask(SIG_SETMASK, &prev_one, NULL); // Unblocking SIGCHLD for its children
- Execve_sachin(token.argv[0], token.argv, environ);
- exit(0); // Should never reach here
- }
- sio_putl(pid);
- sio_puts("\n");
- //Sigprocmask(SIG_BLOCK, &mask_all, NULL); // Blocking all signals
- addjob(job_list, pid, state, cmdline);
- Sigprocmask(SIG_SETMASK, &prev_one, NULL); // Unblokcing all signals
- if (parse_result == PARSELINE_FG) {
- /* Need to wait for it to complete */
- flag = 0;
- while (pid != flag) {
- sio_puts("Before sigsuspend\n");
- Sigsuspend(&empty_set);
- sio_puts("After sigsuspend\n");
- }
- sio_puts("Exited while loop for sigsuspend\n");
- }
- if (parse_result == PARSELINE_BG) {
- print_bg_job(pid);
- }
- return;
- }
- /*****************
- * Signal handlers
- *****************/
- /*
- * <What does sigchld_handler do?>
- */
- void sigchld_handler(int sig)
- {
- sio_puts ("In sigchild handler\n");
- sigset_t mask_all, prev_all;
- pid_t pid;
- Sigfillset(&mask_all);
- int status;
- while ((pid = waitpid(-1, &status, WUNTRACED | WNOHANG)) > 0 ) {
- sio_puts("In while loop of sigchild handler\n");
- flag = pid;
- sio_putl(pid);
- sio_puts("\n");
- sio_putl(flag);
- sio_puts("\n");
- if (WIFEXITED(status)) {
- Sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
- deletejob(job_list, pid);
- Sigprocmask(SIG_SETMASK, &prev_all, NULL);
- sio_puts("Handler reaped child through normal termination \n");
- }
- if (WIFSTOPPED(status)) {
- sio_puts("In stopped part of Sigchild handler\n");
- }
- }
- sio_puts ("Exiting sigchild handler\n");
- return;
- }
- /*
- * <What does sigint_handler do?>
- */
- void sigint_handler(int sig)
- {
- sio_puts ("In Sigint handler\n");
- sigset_t mask_all, prev_one;
- Sigfillset(&mask_all); // To do, might have to block only 3 Signals
- Sigprocmask(SIG_BLOCK, &mask_all, &prev_one);
- pid_t process_id = fgpid(job_list);
- Sigprocmask(SIG_SETMASK, &prev_one, NULL);
- if (process_id == 0)
- return;
- Kill(-process_id, SIGINT);
- return;
- }
- /*
- * <What does sigtstp_handler do?>
- */
- void sigtstp_handler(int sig)
- {
- sio_puts ("In Sigtstp handler\n");
- sigset_t mask_all, prev_one;
- Sigfillset(&mask_all); // To do, might have to block only 3 Signals
- Sigprocmask(SIG_BLOCK, &mask_all, &prev_one);
- pid_t process_id = fgpid(job_list);
- Sigprocmask(SIG_SETMASK, &prev_one, NULL);
- if (process_id == 0)
- return;
- Kill(-process_id, SIGTSTP);
- return;
- }
Advertisement
Add Comment
Please, Sign In to add comment