Esempio n. 1
0
/* If dsh is running interactively as the foreground job
 * then set the process group and signal handlers
 * */
void init_dsh(){
	// in batch mode, STDIN_FILENO is not associated to terminal input.
	dsh_terminal_fd = STDIN_FILENO;
	dsh_is_interactive = isatty(dsh_terminal_fd);

	if(dsh_is_interactive) {
		/* Loop until we are in the foreground.  */
		DEBUG("dsh run as foreground");
		while(tcgetpgrp(dsh_terminal_fd) != (dsh_pgid = getpgrp())){
            // SIGTTIN: (SIGnal due to TeleType INput)
			kill(-dsh_pgid, SIGTTIN); /* Request for terminal input */
		}

		/* Ignore interactive and job-control signals.
		* If tcsetpgrp() is called by a member of a background process
		* group in its session, and the calling process is not blocking or
		* ignoring SIGTTOU,  a SIGTTOU signal is sent to all members of
		* this background process group.
		*/
        // register signal handler. ignore all the
        // SIGTTOU (SIGnal due to TeleType OUtput) is the corresponding signal when a backgrounded (nohuped, etc) job tries to output to the terminal.
		signal(SIGTTOU, SIG_IGN);
		dsh_pgid = getpid();
		if(setpgid(dsh_pgid, dsh_pgid) < 0) {
			perror("Couldn't put the dsh in its own process group");
			exit(EXIT_FAILURE);
		}
		seize_tty(dsh_pgid);
		printf("\n--- Hi, you are using dsh shell, have fun! ---\n\n");
	}
	else{
		DEBUG("dsh run as background");
	}
}
Esempio n. 2
0
void init_dsh() 
{

	dsh_terminal_fd = STDIN_FILENO;

	/* isatty(): test whether a file descriptor refers to a terminal 
	 * isatty() returns 1 if fd is an open file descriptor referring to a
 	 * terminal; otherwise 0 is returned, and errno is set to indicate the error.
 	 * */
	dsh_is_interactive = isatty(dsh_terminal_fd);

  	/* See if we are running interactively.  */
	if(dsh_is_interactive) {
		/* Loop until we are in the foreground.  */
		while(tcgetpgrp(dsh_terminal_fd) != (dsh_pgid = getpgrp()))
			kill(- dsh_pgid, SIGTTIN); /* Request for terminal input */

		/* Ignore interactive and job-control signals.
		* If tcsetpgrp() is called by a member of a background process 
		* group in its session, and the calling process is not blocking or
		* ignoring SIGTTOU,  a SIGTTOU signal is sent to all members of 
		* this background process group.
		*/
		signal(SIGTTOU, SIG_IGN);

		/* Put the dsh in our own process group.  */
		dsh_pgid = getpid();
		if(setpgid(dsh_pgid, dsh_pgid) < 0) {
			perror("Couldn't put the dsh in its own process group");
			exit(EXIT_FAILURE);
		}
		seize_tty(dsh_pgid);
	} 
}
Esempio n. 3
0
/* Creates the context for a new child by setting the pid, pgid and tcsetpgrp */
void new_child(job_t *j, process_t *p, bool fg)
{
         /* establish a new process group, and put the child in
          * foreground if requested
          */

         /* Put the process into the process group and give the process
          * group the terminal, if appropriate.  This has to be done both by
          * the dsh and in the individual child processes because of
          * potential race conditions.  
          * */

  p->pid = getpid();

         /* also establish child process group in child to avoid race (if parent has not done it yet). */
  set_child_pgid(j, p);

  if(fg) // if fg is set
		seize_tty(j->pgid); // assign the terminal

         /* Set the handling for job control signals back to the default. */
  signal(SIGTTOU, SIG_DFL);
}
Esempio n. 4
0
/* 
 * builtin_cmd - If the user has typed a built-in command then execute
 * it immediately.  
 */
bool builtin_cmd(job_t *last_job, int argc, char **argv) 
{

	    /* check whether the cmd is a built in command
        */

  if (!strcmp("quit", argv[0])) {
    /* Your code here */
    exit(EXIT_SUCCESS);
  }
  else if (!strcmp("jobs", argv[0])) {
    /* Your code here */
    job_t* currentJob = active_jobs_head;
    job_t* deletedJob = NULL;

    while(currentJob != NULL) {
      // print active jobs and then change notified to 0

      //if((currentJob->first_process)->completed == true && currentJob->notified == false) {

      //need to check if every process has completed for a job to be complete, not just the first process
      if (job_is_completed(currentJob) == true)
      {
        printf("%d (Completed): %s\n", currentJob->pgid, currentJob->commandinfo);
        deletedJob = currentJob;

         //currentJob->notified = true;
      }
      //otherwise it is stopped
      else if (job_is_stopped(currentJob) == true)
      {
        printf("%d (Stopped): %s\n", currentJob->pgid, currentJob->commandinfo);
      }

      else
      {
        printf("%d (Running): %s\n", currentJob->pgid, currentJob->commandinfo);
      }

      currentJob = currentJob->next;

      // delete job after it is completed, don't need to save notified 
     
      if (deletedJob != NULL) 
      {
        if (deletedJob == active_jobs_head)
        {
          active_jobs_head = deletedJob->next;
          free_job(deletedJob); //TBD warning about this?
        }
        else
        {
          delete_job(deletedJob, active_jobs_head);
        }
        deletedJob = NULL;
      }
    }
    return true;
  }

  else if (!strcmp("cd", argv[0])) {
    int chdir_return = chdir(argv[1]);
    if(chdir_return == -1) {
      printf("cd: %s: No such file or directory\n", argv[1]);
    }
    return true;
  }
  else if (!strcmp("bg", argv[0])) {
    /* Your code here */
    job_t* currentJob = active_jobs_head;
    process_t* p2;

    if(argv[1] == NULL) 
    {
      // continue most recent stopped job

      //use find_last_job
      currentJob = find_last_job(active_jobs_head);

      continue_job(currentJob);
      seize_tty(currentJob->pgid);


      p2 = currentJob->first_process;

      while(p2 != NULL)
      {
        p2->stopped = false;
        
        struct sigaction action;
        action.sa_sigaction = sighandler;

        sigfillset(&action.sa_mask);
        action.sa_flags = SA_SIGINFO;
        sigaction(SIGCHLD, &action, NULL);

        p2 = p2->next;
      }
      seize_tty(getpid());
    }

    else 
    {
      pid_t job_number = atoi(argv[1]);

      
      while(currentJob != NULL) {
        // Need to eventually iterate through all processes?
        
        if((job_is_stopped(currentJob)) && currentJob->pgid == job_number) {
          //seize_tty(currentJob->pgid);
          continue_job(currentJob); 
          seize_tty(currentJob->pgid);

          p2 = currentJob->first_process;
          while (p2 != NULL)
          {
            p2->stopped = false; 

            struct sigaction action;
            action.sa_sigaction = sighandler;

            sigfillset(&action.sa_mask);
            action.sa_flags = SA_SIGINFO;
            sigaction(SIGCHLD, &action, NULL);
            p2 = p2->next;
          }

          seize_tty(getpid());
          break;
        }
        else if (currentJob->pgid == job_number) {
          printf("%s\n", "This process wasn't stopped`");
        }
        else {
          printf("%s\n", "This job number is not the requested one");
        }
        currentJob = currentJob->next;
      }
    }
    return true;
  }


  else if (!strcmp("fg", argv[0])) {
    /* Your code here */
    job_t* currentJob = active_jobs_head;
    process_t* p2;

    if(argv[1] == NULL) {
      // continue most recent stopped job

      //use find_last_job
      currentJob = find_last_job(active_jobs_head);
      continue_job(currentJob);
      seize_tty(currentJob->pgid);


      p2 = currentJob->first_process;

      while(p2 != NULL)
      {
        waiting(p2);
        p2 = p2->next;
      }
      seize_tty(getpid());
    }
    else {
      pid_t job_number = atoi(argv[1]);

      
      while(currentJob != NULL) {
        
        
        if((job_is_stopped(currentJob)) && currentJob->pgid == job_number) {
          //seize_tty(currentJob->pgid);
          continue_job(currentJob); 
          seize_tty(currentJob->pgid);

          p2 = currentJob->first_process;
          while (p2 != NULL)
          {
            waiting(p2);
            p2 = p2->next;
          }
          seize_tty(getpid());
          break;
        }
        else if (currentJob->pgid == job_number) {
          printf("%s\n", "This process wasn't stopped`");
        }
        else {
          printf("%s\n", "This job number is not the requested one");
        }
        currentJob = currentJob->next;
      }
    }
    return true;
  }
  /* not a builtin command */
  return false;
}
Esempio n. 5
0
void spawn_job(job_t *j, bool fg) 
{

  pid_t pid;
  process_t *p;
  int countProcess = 0;
  int loopCounter = -1;
  int i;


  //count number of processes in the job
  for(p = j->first_process; p; p = p->next)
  {
    countProcess++;
  } 

  //printf("count process: %d \n", countProcess);

  int pipefd[countProcess-1][2]; //initialize 2-dimensional array [number of process][input/output]
  //printf("test");

  //open all pipes
  if(countProcess > 1)
  {
    for(i = 0; i < (countProcess-1); i++)
    {
      //printf("piped %d \n", i);
      pipe(pipefd[i]);
    }
  }


  for(p = j->first_process; p; p = p->next) {

	  /* YOUR CODE HERE? */
	  /* Builtin commands are already taken care earlier */
 
    loopCounter++;

    switch (pid = fork()) {
      // int status;

      case -1: /* fork failure */
        perror("fork");
        exit(EXIT_FAILURE);

      case 0: /* child process  */
        p->pid = getpid();	    
        new_child(j, p, fg);

	    /* YOUR CODE HERE?  Child-side code for new process. */

        if (p->ifile != NULL)
        {
          int fd = open(p->ifile, O_RDONLY);
          dup2(fd, STDIN_FILENO);
        }

        if (p->ofile != NULL)
        {
          int fd = open(p->ofile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
          dup2(fd, STDOUT_FILENO);
        }

        //pipe
        if(countProcess > 1)
        {
          //printf("begin piping \n");
          //first process is output        

          //need to loop through number of process and close all pipes
          if(p == j->first_process)
          {

            dup2(pipefd[loopCounter][1], 1); //duplicate output as output for next process 
            closePipe(pipefd, countProcess);

          }  

          //last process
          else if (p->next == NULL)
          {
            dup2(pipefd[loopCounter-1][0], 0);
            closePipe(pipefd, countProcess);

          }

          //for middle: dup both input and output
          
          else
          {
            dup2(pipefd[loopCounter][1], 1);
            dup2(pipefd[loopCounter-1][0], 0);

            closePipe(pipefd, countProcess);


          }

        }

        printf("%d (Launched): %s\n", j->pgid, j->commandinfo);

        execvp(p->argv[0], p->argv);
        perror("New child should have done an exec");
        exit(EXIT_FAILURE);  /* NOT REACHED */
        break;    /* NOT REACHED */

      default: /* parent */
        /* establish child process group */
        p->pid = pid;
        set_child_pgid(j, p);

        /* YOUR CODE HERE?  Parent-side code for new process.  */


        if (p->next == NULL) //if last process
        {
          process_t *p2;

          p2 = j->first_process;
          while(p2 != NULL)
          {
            //printf("waiting for process \n");

            //if fg true waiting, else bg stuff

            if(fg == true)
            {
              waiting(p2);
            }
            else
            {
              struct sigaction action;
              action.sa_sigaction = sighandler;

              sigfillset(&action.sa_mask);
              action.sa_flags = SA_SIGINFO;
              sigaction(SIGCHLD, &action, NULL);
            }
            
            closePipe(pipefd, countProcess);


            p2 = p2->next;
          }
        }

        //wait for child to finish
    }

    /* YOUR CODE HERE?  Parent-side code for new job.*/
    //printf("assign terminal back to dsh\n");
	  seize_tty(getpid()); // assign the terminal back to dsh

  }
}