SHARE
TWEET

Untitled

a guest Dec 8th, 2019 68 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //
  2. // tsh - A tiny shell program with job control
  3. //
  4. // <Put your name and login ID here>
  5. //Numair Baig
  6. //
  7.  
  8. using namespace std;
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <unistd.h>
  13. #include <string.h>
  14. #include <ctype.h>
  15. #include <signal.h>
  16. #include <sys/types.h>
  17. #include <sys/wait.h>
  18. #include <errno.h>
  19. #include <string>
  20.  
  21. #include "globals.h"
  22. #include "jobs.h"
  23. #include "helper-routines.h"
  24.  
  25. //
  26. // Needed global variable definitions
  27. //
  28.  
  29. static char prompt[] = "tsh> ";
  30. int verbose = 0;
  31.  
  32. //
  33. // You need to implement the functions eval, builtin_cmd, do_bgfg,
  34. // waitfg, sigchld_handler, sigstp_handler, sigint_handler
  35. //
  36. // The code below provides the "prototypes" for those functions
  37. // so that earlier code can refer to them. You need to fill in the
  38. // function bodies below.
  39. //
  40.  
  41. void eval(char *cmdline);
  42. int builtin_cmd(char **argv);
  43. void do_bgfg(char **argv);
  44. void waitfg(pid_t pid);
  45.  
  46. void sigchld_handler(int sig);
  47. void sigtstp_handler(int sig);
  48. void sigint_handler(int sig);
  49.  
  50. //
  51. // main - The shell's main routine
  52. //
  53. int main(int argc, char **argv)
  54. {
  55.   int emit_prompt = 1; // emit prompt (default)
  56.  
  57.   //
  58.   // Redirect stderr to stdout (so that driver will get all output
  59.   // on the pipe connected to stdout)
  60.   //
  61.   dup2(1, 2);
  62.  
  63.   /* Parse the command line */
  64.   char c;
  65.   while ((c = getopt(argc, argv, "hvp")) != EOF) {
  66.     switch (c) {
  67.     case 'h':             // print help message
  68.       usage();
  69.       break;
  70.     case 'v':             // emit additional diagnostic info
  71.       verbose = 1;
  72.       break;
  73.     case 'p':             // don't print a prompt
  74.       emit_prompt = 0;  // handy for automatic testing
  75.       break;
  76.     default:
  77.       usage();
  78.     }
  79.   }
  80.  
  81.   //
  82.   // Install the signal handlers
  83.   //
  84.  
  85.   //
  86.   // These are the ones you will need to implement
  87.   //
  88.   Signal(SIGINT,  sigint_handler);   // ctrl-c
  89.   Signal(SIGTSTP, sigtstp_handler);  // ctrl-z
  90.   Signal(SIGCHLD, sigchld_handler);  // Terminated or stopped child
  91.  
  92.   //
  93.   // This one provides a clean way to kill the shell
  94.   //
  95.   Signal(SIGQUIT, sigquit_handler);
  96.  
  97.   //
  98.   // Initialize the job list
  99.   //
  100.   initjobs(jobs);
  101.  
  102.   //
  103.   // Execute the shell's read/eval loop
  104.   //
  105.   for(;;) {
  106.     //
  107.     // Read command line
  108.     //
  109.     if (emit_prompt) {
  110.       printf("%s", prompt);
  111.       fflush(stdout);
  112.     }
  113.  
  114.     char cmdline[MAXLINE];
  115.  
  116.     if ((fgets(cmdline, MAXLINE, stdin) == NULL) && ferror(stdin)) {
  117.       app_error("fgets error");
  118.     }
  119.     //
  120.     // End of file? (did user type ctrl-d?)
  121.     //
  122.     if (feof(stdin)) {
  123.       fflush(stdout);
  124.       exit(0);
  125.     }
  126.  
  127.     //
  128.     // Evaluate command line
  129.     //
  130.     eval(cmdline);
  131.     fflush(stdout);
  132.     fflush(stdout);
  133.   }
  134.  
  135.   exit(0); //control never reaches here
  136. }
  137.  
  138. /////////////////////////////////////////////////////////////////////////////
  139. //
  140. // eval - Evaluate the command line that the user has just typed in
  141. //
  142. // If the user has requested a built-in command (quit, jobs, bg or fg)
  143. // then execute it immediately. Otherwise, fork a child process and
  144. // run the job in the context of the child. If the job is running in
  145. // the foreground, wait for it to terminate and then return.  Note:
  146. // each child process must have a unique process group ID so that our
  147. // background children don't receive SIGINT (SIGTSTP) from the kernel
  148. // when we type ctrl-c (ctrl-z) at the keyboard.
  149. //
  150. void eval(char *cmdline)
  151. {
  152.   /* Parse command line */
  153.   //
  154.   // The 'argv' vector is filled in by the parseline
  155.   // routine below. It provides the arguments needed
  156.   // for the execve() routine, which you'll need to
  157.   // use below to launch a process.
  158.   //
  159.     pid_t pid;//keeps track of pid
  160.   char *argv[MAXARGS];
  161.  
  162.   //
  163.   // The 'bg' variable is TRUE if the job should run
  164.   // in background mode or FALSE if it should run in FG
  165.   //
  166.   int bg = parseline(cmdline, argv);
  167.     sigset_t mask;//block of sigchild
  168.   if (argv[0] == NULL)  
  169.     return;   /* ignore empty lines */
  170. //     if(strcmp(argv[0],"quit") == 0)//if first command line argument is quit, exit the program
  171. //     {
  172. //         //uses strcmp to avoid pointer cmp w/ string
  173. //         exit(0);//exits program
  174. //     }
  175. //     else if(strcmp(argv[0],"fg") == 0)//if first command line argument is foreground, run a foreground job
  176. //     {
  177. //         return 1;//return for proof of job
  178. //     }
  179.     struct job_t *job;//creates job obj ptr
  180.     if(!builtin_cmd(argv))//if argv vector does not contain built in command
  181.     {
  182.         sigemptyset(&mask);//initializes signal stb to empty set
  183.         sigaddset(&mask, SIGCHLD);//adds sigchild signal to set
  184.         sigprocmask(SIG_BLOCK, &mask, NULL);//blocking until child is created
  185.        
  186.         if((pid = fork()) == 0)//fork and execute
  187.         {
  188.            sigprocmask(SIG_UNBLOCK, &mask, NULL);
  189.             setpgid(0,0);
  190.             // execvp(argv[0], argv);//executes first argv with full vec vp to specify path
  191.             if(execve(argv[0], argv, environ) < 0)
  192.             {
  193.                 printf("%s: Command not found.\n", argv[0]);
  194.                 exit(0);//exits - terminates child
  195.             }
  196.         }
  197.         addjob(jobs, pid, bg ? BG : FG, cmdline);//adds job
  198.         sigprocmask(SIG_UNBLOCK, &mask, NULL);//to prevent queue from clogging
  199.         //has job and pid
  200.         //turnary op checks if background process, if not, then foreground process
  201.         if(!bg)//if not background
  202.         {
  203.             //wait(NULL);//blocks calling process until signal is received - waits for child
  204.             waitfg(pid);
  205.         }
  206.         else//if is background
  207.         {
  208.            job = getjobpid(jobs, pid); //gets job pid
  209.             printf("[%d] (%d) %s/n", job->jid, pid, cmdline);//print based on desired statement from rtest
  210.             //[1] (83) ./myspin 1 &
  211.         }
  212.     }
  213.   return;
  214. }
  215.  
  216.  
  217. /////////////////////////////////////////////////////////////////////////////
  218. //
  219. // builtin_cmd - If the user has typed a built-in command then execute
  220. // it immediately. The command name would be in argv[0] and
  221. // is a C string. We've cast this to a C++ string type to simplify
  222. // string comparisons; however, the do_bgfg routine will need
  223. // to use the argv array as well to look for a job number.
  224. //
  225. int builtin_cmd(char **argv) //built in command function
  226. {
  227.   string cmd(argv[0]);
  228.    
  229.     if(cmd == "quit")//if first command line argument is quit
  230.     {
  231.         exit(0);//exits shell - performs a quit
  232.     }
  233.     else if(cmd == "fg")//if first command is to run a foreground process
  234.     {
  235.         do_bgfg(argv);//runs background foreground
  236.         return 1;//returns 1 to verify process performed
  237.     }
  238.     else if(cmd == "bg")//if first command is to run a background process
  239.     {
  240.         //move process to background and quit shell
  241.         do_bgfg(argv);//runs background foreground
  242.         return 1;//return 1 to verify process performed
  243.     }
  244.     else if(cmd == "jobs")//if first command is to view jobs
  245.     {
  246.         listjobs(jobs);//lists the jobs
  247.         return 1;//return 1 to verify process performed
  248.     }
  249.   return 0;     /* not a builtin command */
  250. }
  251.  
  252. /////////////////////////////////////////////////////////////////////////////
  253. //
  254. // do_bgfg - Execute the builtin bg and fg commands
  255. //
  256. void do_bgfg(char **argv)
  257. {
  258.   struct job_t *jobp=NULL;
  259.    
  260.   /* Ignore command if no argument */
  261.   if (argv[1] == NULL) {
  262.     printf("%s command requires PID or %%jobid argument\n", argv[0]);
  263.     return;
  264.   }
  265.    
  266.   /* Parse the required PID or %JID arg */
  267.   if (isdigit(argv[1][0])) {
  268.     pid_t pid = atoi(argv[1]);
  269.     if (!(jobp = getjobpid(jobs, pid))) {
  270.       printf("(%d): No such process\n", pid);
  271.       return;
  272.     }
  273.   }
  274.   else if (argv[1][0] == '%') {
  275.     int jid = atoi(&argv[1][1]);
  276.     if (!(jobp = getjobjid(jobs, jid))) {
  277.       printf("%s: No such job\n", argv[1]);
  278.       return;
  279.     }
  280.   }    
  281.   else {
  282.     printf("%s: argument must be a PID or %%jobid\n", argv[0]);
  283.     return;
  284.   }
  285.  
  286.   //
  287.   // You need to complete rest. At this point,
  288.   // the variable 'jobp' is the job pointer
  289.   // for the job ID specified as an argument.
  290.   //
  291.   // Your actions will depend on the specified command
  292.   // so we've converted argv[0] to a string (cmd) for
  293.   // your benefit.
  294.   //
  295.   string cmd(argv[0]);
  296.     int pid = jobp->pid;
  297.     //kill with SIGCONT
  298.     kill(-pid, SIGCONT);// - kills whole process group
  299.     if(cmd != "fg")//check if command is foreground
  300.     {
  301.         jobp->state = BG;//set jobp state to background
  302.         printf("[%d] (%d) %s", jobp->jid, jobp->pid, jobp->cmdline);//command of job
  303.     }
  304.     else
  305.     {
  306.         jobp->state = FG;//set jobp state
  307.         waitfg(pid);
  308.     }
  309.    
  310.   return;
  311. }
  312.  
  313. /////////////////////////////////////////////////////////////////////////////
  314. //
  315. // waitfg - Block until process pid is no longer the foreground process
  316. //
  317. void waitfg(pid_t pid)
  318. {
  319.     struct job_t *job = getjobpid(jobs, pid);//gets job using pid
  320.    
  321.     if(pid != 0 && job != NULL)//to avoid seg fault
  322.     {
  323.         while(job->state == FG)//if job is a foreground job
  324.         {
  325.             sleep(1);//wait then return
  326.         }
  327.     }
  328.     return;
  329. }
  330.  
  331. /////////////////////////////////////////////////////////////////////////////
  332. //
  333. // Signal handlers
  334. //
  335.  
  336.  
  337. /////////////////////////////////////////////////////////////////////////////
  338. //
  339. // sigchld_handler - The kernel sends a SIGCHLD to the shell whenever
  340. //     a child job terminates (becomes a zombie), or stops because it
  341. //     received a SIGSTOP or SIGTSTP signal. The handler reaps all
  342. //     available zombie children, but doesn't wait for any other
  343. //     currently running children to terminate.  
  344. //
  345. void sigchld_handler(int sig)
  346. {
  347.     pid_t pid;
  348.     int status;
  349.     //struct job_t *job;//using job struct
  350.     while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0)//WNOHANG doesn't wait for process
  351.     {//WUNTRACED check for stop signal
  352.         //job = getjobpid(jobs, pid);
  353.         if(WIFSTOPPED(status))//signal not modified
  354.         {
  355.             getjobpid(jobs, pid)->state = ST;//set jobpid state to stop
  356.             int jid = pid2jid(pid);//find pid return jid
  357.             printf("Job [%d] (%d) stopped by signal %d\n", jid, pid, WSTOPSIG(status));
  358.         }
  359.         else if(WIFSIGNALED(status))//looks for error signal
  360.         {
  361.             int jid = pid2jid(pid);//gets jid from pid
  362.             printf("Job [%d] (%d) terminated by signal %d\n", jid, pid, WTERMSIG(status));
  363.             deletejob(jobs, pid);//deletes job after termination
  364.         }
  365.         else if(WIFEXITED(status))
  366.         {
  367.            deletejob(jobs, pid);//deletes job after termination  
  368.         }
  369.     }
  370.    
  371.     return;
  372. }
  373.  
  374. /////////////////////////////////////////////////////////////////////////////
  375. //
  376. // sigint_handler - The kernel sends a SIGINT to the shell whenver the
  377. //    user types ctrl-c at the keyboard.  Catch it and send it along
  378. //    to the foreground job.  
  379. //
  380. void sigint_handler(int sig) //passes sig int signal
  381. {
  382.     int pid = fgpid(jobs);//gets pid of foreground
  383.     if(pid != 0)//if not a child
  384.     {//to kill child use sigchild
  385.         int pass = kill(-pid, sig); //send signal to foreground
  386.         //return -1 for failure
  387.         if(pass < 0)
  388.         {
  389.             unix_error("kill error");//if attempt to kill doesn't exist
  390.         }
  391.     }
  392.     return;
  393. }
  394.  
  395. /////////////////////////////////////////////////////////////////////////////
  396. //
  397. // sigtstp_handler - The kernel sends a SIGTSTP to the shell whenever
  398. //     the user types ctrl-z at the keyboard. Catch it and suspend the
  399. //     foreground job by sending it a SIGTSTP.  
  400. //
  401. void sigtstp_handler(int sig) //passes sig stop signal
  402. {
  403.      int pid = fgpid(jobs);//gets pid of foreground
  404.     if(pid != 0)//if not a child
  405.     {
  406.         int pass = kill(-pid, sig); //send signal to foreground
  407.        
  408.         if(pass < 0)
  409.         {
  410.             unix_error("kill error");
  411.         }
  412.     }
  413.     return;
  414. }
  415.  
  416. /*********************
  417.  * End signal handlers
  418.  *********************/
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top