void builtincont(struct cmdline_tokens *tok, int state){ if (tok->argc < 2){ // app_error("Usage: %s [%jid/pid]\n", tok->argv[0]); return; } pid_t pid; /* JID */ if (tok->argv[1][0]=='%'){ int jid = atoi((char *)(tok->argv[1] + sizeof(char))); pid = jid2pid(jid); if (!pid) app_error("No such jid \n"); } else{ /* PID case */ pid = atoi(tok->argv[1]); if (!pid2jid(pid)) app_error("No such pid \n"); } /* Common to both JID & PID */ Kill(-pid, SIGCONT); changestate(job_list, pid, state); if (state==BG){ printf("[%d] (%d) %s\n", pid2jid(pid), pid, getjobpid(job_list,pid)->cmdline); } if (state==FG){ wait_for_fg(pid); } }
/* * 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 **environ) { int bg; /* should the job run in bg or fg? */ struct cmdline_tokens tok; char* s; int jid, pid, state, fd1, fd2, fdstdin, fdstdout; sigset_t mask; struct job_t* job; /* Parse command line */ bg = parseline(cmdline, &tok); if (bg == -1) return; /* parsing error */ if (tok.argv[0] == NULL) return; /* ignore empty lines */ if (tok.infile != NULL) { fd1 = open(tok.infile, O_RDONLY, 0); if (fd1 == -1) app_error("open file fin error"); fdstdin = dup(STDIN_FILENO); dup2(fd1, STDIN_FILENO); } if (tok.outfile != NULL) { fd2 = open(tok.outfile, O_WRONLY, 0); if (fd2 == -1) app_error("open file fout error"); fdstdout = dup(STDOUT_FILENO); dup2(fd2, STDOUT_FILENO); } if (tok.builtins != BUILTIN_NONE) { if (tok.builtins == BUILTIN_QUIT) exit(0); else if (tok.builtins == BUILTIN_JOBS) listjobs(job_list, 1); else if (tok.builtins == BUILTIN_BG || tok.builtins == BUILTIN_FG) { s = tok.argv[1]; pid = jid = -1; if (s[0] == '%') { sscanf(&s[1], "%d", &jid); pid = jid2pid(jid); } else { sscanf(s, "%d", &pid); jid = pid2jid(pid); } if (jid == -1 || pid == -1) app_error("fail to get pid or jid"); job = getjobpid(job_list, pid); job->state = tok.builtins == BUILTIN_FG ? FG : BG; kill(pid, SIGCONT); waitjobpid(pid, job->state, job->cmdline); } } else { sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGTSTP); sigprocmask(SIG_BLOCK, &mask, NULL); if ((pid = fork()) == 0) { //Child runs user job setpgid(0, 0); sigprocmask(SIG_UNBLOCK, &mask, NULL); if (execve(tok.argv[0], tok.argv, environ) < 0) { printf("%s: Command not found.\n", tok.argv[0]); return; } } else { state = bg ? BG : FG; addjob(job_list, pid, state, cmdline); sigprocmask(SIG_UNBLOCK, &mask, NULL); waitjobpid(pid, state, cmdline); } } if (tok.infile != NULL) { close(fd1); dup2(fdstdin, STDIN_FILENO); } if (tok.outfile != NULL) { close(fd2); dup2(fdstdout, STDOUT_FILENO); } return; }
void do_bgfg(char **argv) { if(!argv[1]) { //Checks if there is a argument with the command printf("%s command requires PID or %% jobid argument\n", argv[0]); return; } int pid; if(argv[1][0] == '%') { // Checks if it is a jobid argument char* argStr = argv[1] + 1; //cuts the % sign from the argument int jid; sscanf(argStr, "%d", &jid); //convert the string to int if(!isStrDigits(argStr, argv)) { //check if the string is a number return; } if(getjobjid(jobs, jid) == NULL) { //check if the job exists printf("%%%d: No such job \n", jid); return; } pid = jid2pid(jid); } else { char* argStr = argv[1]; sscanf(argStr, "%d", &pid); //convert string to int if(!isStrDigits(argStr, argv)) { //check it the string is a number return; } if(getjobpid(jobs, (pid_t) pid) == NULL) { //check if the job exists printf("(%d): No such process \n", pid); return; } } kill(-pid, SIGCONT); // If it is as fg process than wait for ot to finnish if (strcmp(argv[0], "fg") == 0) { getjobpid(jobs, pid)->state = FG; //job state changed to FG waitfg(pid); return; } getjobpid(jobs, pid)->state = BG; //job state changed to BG for (int i = 0; i < MAXJOBS; i++) { if (jobs[i].pid == pid) { printf("[%d] (%d) %s", pid2jid(pid), pid, jobs[i].cmdline); } } return; }
/* * 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) { int bg; /* should the job run in bg or fg? */ int job_state; /* initial value of job BG or FG based on bg */ int status; int check; struct cmdline_tokens tok; pid_t pid = -255; // Initialzing to int jid = -255; // dummy values sigset_t mask; sigset_t mask2; int flag = 0; //Used while processing "fg" built in command int infile_fd ; //file descriptor to be used for infile if specified in job int outfile_fd ; //file descriptor to be used for outfile if specified in job //Get shell pid tsh_pid = getpid(); //Intialize mask for blocked signal //Block SIGCHLD SIGINT SIGTSTP signals Sigemptyset(&mask); Sigemptyset(&mask2); Sigaddset(&mask,SIGCHLD); Sigaddset(&mask,SIGINT); Sigaddset(&mask2,SIGINT); Sigaddset(&mask,SIGTSTP); Sigaddset(&mask2,SIGTSTP); Sigprocmask(SIG_BLOCK,&mask,NULL); /* Parse command line */ bg = parseline(cmdline, &tok); if (bg == -1) return; /* parsing error */ if (tok.argv[0] == NULL) return; /* ignore empty lines */ /* If tok is a BUILTIN shell command */ if (tok.builtins != BUILTIN_NONE) { switch(tok.builtins) { //Built in command quit : //Send SIGKILL to all processes in shell case BUILTIN_QUIT : tsh_pid = getpid(); kill(-tsh_pid,SIGKILL); break; //List out all jobs when "jobs" called //Also open output file if redirection specified and //redirect jobs output to the new file's descriptor case BUILTIN_JOBS : if (tok.outfile != NULL) { outfile_fd = open(tok.outfile , O_WRONLY); listjobs(job_list,outfile_fd); break; } else listjobs(job_list,STDOUT_FILENO); break; // Parse job id or pid given with bg command // Change state from ST to BG in job_list // Send SIGCONT signal to job case BUILTIN_FG : if(*(char *)(tok.argv[1]) == '%' ) { jid = atoi( (((char *)(tok.argv[1])) + 1) ); pid = jid2pid(jid); } else { pid = atoi(tok.argv[1]); jid = pid2jid(pid); } change_job_state(job_list,pid,FG); flag = 1; //flag set because we want to jump into else clause below // to process resumed job as a foreground job Kill(-pid,SIGCONT); break; //Parse job id or pid given with bg command // Change state from ST to BG in job_list // Send SIGCONT signal to job case BUILTIN_BG : if(*(char *)(tok.argv[1]) == '%' ) { jid = atoi( (((char *)(tok.argv[1])) + 1) ); pid = jid2pid(jid); } else { pid = atoi(tok.argv[1]); jid = pid2jid(pid); } printjob(pid,STDOUT_FILENO); change_job_state(job_list,pid,BG); Kill(-pid,SIGCONT); break; case BUILTIN_NONE : break; default : break; } } //If tok is a external program to be run by shell else if ((tok.builtins == BUILTIN_NONE) || (flag == 1)) { if (flag == 1) bg = 0; if(!bg) job_state = FG; else job_state = BG; //Child process if ((pid = Fork()) == 0) { setpgid(0,0); //Start process in new group Signal(SIGINT, SIG_DFL); /* ctrl-c from child handled by parent's sigchld */ addjob(job_list,getpid(),job_state,cmdline); // If input/output redirection specified open given file and point STDIN/STDOUT descriptor // to new file's file descriptor if (tok.infile != NULL) { infile_fd = open(tok.infile , O_RDONLY); dup2(infile_fd,STDIN_FILENO); } if (tok.outfile != NULL) { outfile_fd = open(tok.outfile , O_WRONLY); dup2(outfile_fd,STDOUT_FILENO); } //Unblock masks inherited from parent process //and execute program using exec Sigprocmask(SIG_UNBLOCK,&mask,NULL); Execve(tok.argv[0],tok.argv,environ); } //Parent process //Add child to job list and unblock signal,also set fg_pid if job is foreground job addjob(job_list,pid,job_state,cmdline); if(!bg) fg_pid = pid; Sigprocmask(SIG_UNBLOCK,&mask2,NULL); //Until foreground process terminates SIGCHLD functionality is done here , SIGINT and SIGTSTP are handled by handlers if(!bg) { check = waitpid(pid,&status,WUNTRACED); if ((check<0) && (errno!=ECHILD)) unix_error("waitfg : wait pid error\n"); if ((check == pid) && WIFSTOPPED(status)){ print_sigtstp_job(job_list,pid,SIGTSTP,STDOUT_FILENO); //Print message that job was stopped by SIGSTP signal //Change stopped job state in list to ST (stopped) change_job_state(job_list,pid,ST); return; } if ((check == pid) && (WIFSIGNALED(status))) print_sigint_job(job_list,pid,WTERMSIG(status),STDOUT_FILENO); //Print message that job/pid was terminated by a signal deletejob(job_list,pid); Sigprocmask(SIG_UNBLOCK,&mask,NULL); } else { Sigprocmask(SIG_UNBLOCK,&mask,NULL); printjob(pid,STDOUT_FILENO); } } return; }