/** // Implement the job double ended

/** * @file execute.

c * * @brief Implements interface functions between Quash and the environment and * functions that interpret an execute commands. * * @note As you add things to this file you may want to change the method signature */// NOTE: the following website was used to gather more information // for system calls. This information was used to add comments// detailing what was going on in the functions using them.// https://linux.die.

We Will Write a Custom Essay Specifically
For You For Only $13.90/page!


order now

net/man/3/#include “execute.h”#include “deque.h”#include #include #include #include #include #include #include “quash.h”// Remove this and all expansion calls to it/** * @brief Note calls to any function that requires implementation */#define IMPLEMENT_ME() fprintf(stderr, “IMPLEMENT ME: %s(line %d): %s()
“, __FILE__, __LINE__, __FUNCTION__)// Implement the process id double ended queue structureIMPLEMENT_DEQUE_STRUCT( PIDDequeue, pid_t );// Generate the prototypes for the functions of the double ended queuePROTOTYPE_DEQUE( PIDDequeue, pid_t );// Implement the process id double ended queueIMPLEMENT_DEQUE( PIDDequeue, pid_t );// Struct declaration for a jobtypedef struct Job { int jobId; char* cmd; PIDDequeue pid_list;} Job;// Implement the job double ended queue structureIMPLEMENT_DEQUE_STRUCT( JobDequeue, Job );// Generate the prototypes for the functions of the double ended queuePROTOTYPE_DEQUE( JobDequeue, Job );// Implement the job double ended queueIMPLEMENT_DEQUE( JobDequeue, Job );// Pipe array declarationint _pipes22;// Pope index declarationint _pipeLoc = 0;// Declaration for the initiated status of a jobbool isInit = false;// The number for the jobint jobNum = 1;// Double ended queue for jobsJobDequeue jobs;// Double ended queue for process ids// this was done to prevent any issues// that we had coming up when accessing// the process id list of a jobPIDDequeue pids;/*************************************************************************** * Interface Functions ***************************************************************************/// Return a string containing the current working directory.char* get_current_directory(bool* should_free) { // Set the boolean to false *should_free = false; // Create an empty string to hold the current directory char* cwd = NULL; // Set the string to the current directory cwd = getcwd( NULL, 0 ); // Return the current working directory return cwd;}// Returns the value of an environment variable env_varconst char* lookup_env(const char* env_var) { // Create a string to hold the environment variable char* env = NULL; // Set the string to the environment variable env = getenv( env_var ); // Return the variable return env;}// Check the status of background jobsvoid check_jobs_bg_status() { // If the job queue is empty then there are no jobs // to print out, so end execution of this // function if ( is_empty_JobDequeue( &jobs ) ) { return; } // Get the number of jobs int numOfJobs = length_JobDequeue( &jobs ); // Iterate through each one of the jobs for ( int i = 0; i < numOfJobs; i++ ) { // Set a local variable to the current job Job curJob = pop_front_JobDequeue( &jobs ); // Grab the queue of processes PIDDequeue curJobPids = curJob.

pid_list; // Get the current process id pid_t curPid = peek_front_PIDDequeue( &curJobPids ); // Get the number of processes int numOfPids = length_PIDDequeue( &curJobPids ); // Iterate through each of the processes for ( int j = 0; j < numOfPids; j++ ) { // Set a local variable to the iterating process id pid_t curPid2 = pop_front_PIDDequeue( &curJobPids ); // Create a status variable int status = 0; // If the status of the process id is 0 // push the iterating process id to // the end of the process id queue if ( waitpid( curPid2, &status, WNOHANG ) == 0 ) { push_back_PIDDequeue( &curJobPids, curPid2 ); } } // If there are no process ids for the current job // print that the job is complete, then // get rid of the process id queue. // If there are still processes push the // current job to the end of the job queue if ( is_empty_PIDDequeue( &curJobPids ) ) { // Set a local variable for the job id int curJobId = curJob.jobId; // Set a local variable for the job command char* curJobCmd = curJob.cmd; // Print that the job has completed print_job_bg_complete( curJobId, curPid, curJobCmd ); // Free the memory being used by the job command free( curJobCmd ); // Destroy the process id queue for the current job destroy_PIDDequeue( &curJobPids ); } else { // Push the current job to the end of the job queue push_back_JobDequeue( &jobs, curJob ); } }}// Prints the job id number, the process id of the first process belonging to// the Job, and the command string associated with this jobvoid print_job(int job_id, pid_t pid, const char* cmd) { printf("%d %8d %s
", job_id, pid, cmd); fflush(stdout);}// Prints a start up message for background processesvoid print_job_bg_start(int job_id, pid_t pid, const char* cmd) { printf("Background job started: "); print_job(job_id, pid, cmd);}// Prints a completion message followed by the print jobvoid print_job_bg_complete(int job_id, pid_t pid, const char* cmd) { printf("Completed: "); print_job(job_id, pid, cmd);}/*************************************************************************** * Functions to process commands ***************************************************************************/// Run a program reachable by the path environment variable, relative path, or// absolute pathvoid run_generic(GenericCommand cmd) { // Execute a program with a list of arguments. The `args` array is a NULL // terminated (last string is always NULL) list of strings. The first element // in the array is the executable char* exec = cmd.args0; char** args = cmd.args; // Execute the command that is passed in execvp( exec, args ); // Silenced error // perror("ERROR: Failed to execute program");}// Print stringsvoid run_echo(EchoCommand cmd) { // Print an array of strings.

The args array is a NULL terminated // (last string is always NULL) list of strings. char** str = cmd.args; // Print the sentence as long as the end (NULL string) // is not reached while ( *str != NULL ) { printf( "%s ", *str ); str++; } // Print a new line for corrent formatting printf( "
" ); // Flush the buffer before returning fflush(stdout);}// Sets an environment variablevoid run_export(ExportCommand cmd) { // Write an environment variable const char* env_var = cmd.

env_var; const char* val = cmd.val; // Set the environment setenv( env_var, val, 1 );}// Changes the current working directoryvoid run_cd(CDCommand cmd) { // Get the directory name const char* dir = cmd.dir; // Check if the directory is valid // notify the user of an error if one occurs if (dir == NULL) { perror("ERROR: Failed to resolve path"); return; } // Character array to hold the path char* path = NULL; // Get the path to the directory path = realpath( dir, NULL ); // Check to see if the path was set // notify the user of an error if one occurs if(path == NULL) { perror("ERROR: Failed to resolve path"); return; } // Change the current directory to that // of the path that is set above chdir( path ); // Set the current environment variable "PWD" // to the new path setenv( "PWD", path, 1 ); // Deallocate the memory being used by path // since realpath() is called using NULL free( path );}// Sends a signal to all processes contained in a jobvoid run_kill(KillCommand cmd) { int signal = cmd.sig; int job_id = cmd.job; // Get the total number of jobs int numOfJobs = length_JobDequeue( &jobs ); // Increment through each of the jobs for ( int i = 0; i < numOfJobs; i++ ) { // Set a local variable for the iterating job Job curJob = peek_front_JobDequeue( &jobs ); // Get the job id for the iterating job int curJobId = curJob.jobId; // Check to see if the current job's id is equal // to the cmd job id. If it is go through the // processes of the job and terminate them. Otherwise // pop off the current job and put the at the end of the // job queue.

if( curJobId == job_id ) { // Get the processes of the current job PIDDequeue curJobPids = curJob.pid_list; // Get the number of processes for the job int numOfPids = length_PIDDequeue( &curJobPids ); // Increment through each process for ( int j = 0; j < numOfPids; j++ ) { // Get the current process id pid_t curPid = peek_front_PIDDequeue( &curJobPids ); // Terminate the process kill( curPid, signal ); // Remove the process from the proccess queue pop_front_PIDDequeue( &curJobPids ); } } else { // Pop off the current job Job curJobPopped = pop_front_JobDequeue( &jobs ); // Add it back to the end of the job queue push_back_JobDequeue( &jobs, curJobPopped ); } }}// Prints the current working directory to stdoutvoid run_pwd() { // Initialize boolean to false bool isFree = false; // Get the current directory char* directory = get_current_directory( &isFree ); // Print out the current directory printf( "%s
", directory ); // Deallocate the memory being used by directory free( directory ); // Flush the buffer before returning fflush(stdout);}// Prints all background jobs currently in the job list to stdoutvoid run_jobs() { // Get the number of jobs int numOfJobs = length_JobDequeue( &jobs ); // If the job queue is empty then there // are no jobs to run, so return and // stop execution of this funtion. if ( is_empty_JobDequeue( &jobs ) ) { return; } // Iterate through each of the jobs for ( int i = 0; i < numOfJobs; i++ ) { // Set a local variable to the iterating job Job curJob = pop_front_JobDequeue( &jobs ); // Set a variable for the job's id int curJobId = curJob.jobId; // Set a variable for the job's command char* curJobCmd = curJob.cmd; // Get the process id for the current job pid_t curJobPid = peek_front_PIDDequeue( &curJob.pid_list ); // Print the current job print_job( curJobId, curJobPid, curJobCmd ); // Push the current job to the back of the queue // so that the jobs can be iterated through push_back_JobDequeue( &jobs, curJob ); } // Flush the buffer before returning fflush(stdout);}/*************************************************************************** * Functions for command resolution and process setup ***************************************************************************//** * @brief A dispatch function to resolve the correct @a Command variant * function for child processes. * * This version of the function is tailored to commands that should be run in * the child process of a fork.

* * @param cmd The Command to try to run * * @sa Command */void child_run_command(Command cmd) { CommandType type = get_command_type(cmd); switch (type) { case GENERIC: run_generic(cmd.generic); break; case ECHO: run_echo(cmd.echo); break; case PWD: run_pwd(); break; case JOBS: run_jobs(); break; case EXPORT: case CD: case KILL: case EXIT: case EOC: break; default: fprintf(stderr, "Unknown command type: %d
", type); }}/** * @brief A dispatch function to resolve the correct @a Command variant * function for the quash process. * * This version of the function is tailored to commands that should be run in * the parent process (quash). * * @param cmd The Command to try to run * * @sa Command */void parent_run_command(Command cmd) { CommandType type = get_command_type(cmd); switch (type) { case EXPORT: run_export(cmd.export); break; case CD: run_cd(cmd.cd); break; case KILL: run_kill(cmd.kill); break; case GENERIC: case ECHO: case PWD: case JOBS: case EXIT: case EOC: break; default: fprintf(stderr, "Unknown command type: %d
", type); }}/** * @brief Creates one new process centered around the @a Command in the @a * CommandHolder setting up redirects and pipes where needed * * @note Processes are not the same as jobs.

A single job can have multiple * processes running under it. This function creates a process that is part of a * larger job. * * @note Not all commands should be run in the child process. A few need to * change the quash process in some way * * @param holder The CommandHolder to try to run * * @sa Command CommandHolder */void create_process(CommandHolder holder) { // Read the flags field from the parser bool p_in = holder.flags & PIPE_IN; bool p_out = holder.flags & PIPE_OUT; bool r_in = holder.

flags & REDIRECT_IN; bool r_out = holder.flags & REDIRECT_OUT; bool r_app = holder.flags & REDIRECT_APPEND; // This can only be true if r_out // is true // Set a variable representing the pipe index // to be used when creating navigating the // pipe array int _pipeIndex = 0; // Create a local process id and set to // a new process pid_t localPID = fork(); // If p_out is true, run pipe() with the pipe array if ( p_out ) { // Set the pipe index to the remainder of // the pipeLoc variable and 2 (for the pipe numbers) _pipeIndex = _pipeLoc % 2; // Create the pipes pipe(_pipes_pipeIndex); } // Push the new process to the end // of the process id queue push_back_PIDDequeue( &pids, localPID ); // Actions for the child branch of fork if ( localPID == 0 ) { // If p_in is true update the pipe index // and duplicate the file descriptor at the pipe // index, then close said descriptor if ( p_in ) { // Update pipe index _pipeIndex = (_pipeLoc – 1) % 2; // Duplicate the file descriptor dup2( _pipes_pipeIndex0, STDIN_FILENO ); // Close the descriptor close( _pipes_pipeIndex0 ); } // If p_out is true update the pipe index // and duplicate the file descriptor at the pipe // index, then close said descriptor if ( p_out ) { // Update pipe index _pipeIndex = _pipeLoc % 2; // Duplicate the file descriptor dup2( _pipes_pipeIndex1, STDIN_FILENO ); // Close the descriptor close( _pipes_pipeIndex1 ); } // If r_in is true then we are reading // in from a file.

Open the file and // duplicate the file descriptor. if ( r_in ) { // Open the file for reading ("r") FILE* inFile = fopen( holder.redirect_in, "r" ); // Get the integer descriptor and duplicate it dup2( fileno( inFile ), STDIN_FILENO ); // fclose( inFile ); } // If r_out is true there are two cases // 1. Append to the file (adding to an existing one) // 2. Write to a file (creates a new file with given // name, or clears it if it exists already) if ( r_out ) { // Appending to the file if ( r_app ) { // Open the file for appending ("a") FILE* outFile = fopen( holder.redirect_out, "a" ); // Get the integer descriptor and duplicate it dup2( fileno( outFile ), STDOUT_FILENO ); // fclose( outFile ); } else { // Writing to the file // Open the file for writing ("w") FILE* outFile = fopen( holder.redirect_out, "w" ); // Get the integer descriptor and duplicate it dup2( fileno( outFile ), STDOUT_FILENO ); // fclose( outFile ); } } // Run the child command child_run_command( holder.

cmd ); // Exit exit( 0 ); } else { // Actions for the parent branch of fork // If p_out is true update the pipe index, then // close the descriptor if ( p_out ) { _pipeIndex = _pipeLoc % 2; close( _pipes_pipeIndex1 ); } // Run the parent command parent_run_command( holder.cmd ); }}// Run a list of commandsvoid run_script(CommandHolder* holders) { // Check if the job is initiated. // If it is not then create a new job queue // and set the isInit flag to true. if ( !isInit ) { // set job queue to new job queue jobs = new_JobDequeue( 1 ); isInit = true; } if (holders == NULL) return; check_jobs_bg_status(); if (get_command_holder_type(holders0) == EXIT && get_command_holder_type(holders1) == EOC) { end_main_loop(); return; } // Set the process id queue to a new queue pids = new_PIDDequeue( 1 ); CommandType type; // Run all commands in the `holder` array for (int i = 0; (type = get_command_holder_type(holdersi)) != EOC; ++i) { // Set the pipe index to update as the processes are created _pipeLoc = i; // Create the process create_process(holdersi); } // If the job is not a background job if (!(holders0.flags & BACKGROUND)) { // Iterate through the process ids until the // process id queue is emtpy while ( !is_empty_PIDDequeue( &pids ) ) { // Pop off the first process id pid_t curPID = pop_front_PIDDequeue( &pids ); // Create a variable for the status int curStatus = 0; // Wait for the process to terminate waitpid( curPID, &curStatus, 0 ); } // Destroy the process id queue destroy_PIDDequeue( &pids ); } // If the job is a background job else { // Get the command string char* command = get_command_string(); // Create a variable for the current job // and set its members // Source for below code snippet: // https://stackoverflow.com/questions/32698293/assign-values-to-structure-variables Job curJob; curJob = (Job){ .jobId = jobNum, .cmd = command, .pid_list = pids }; // Increment the number of jobs jobNum++; // Set a local variable for the current job id int curJobId = curJob.jobId; // Set a local variable for te current process id pid_t curPID = peek_front_PIDDequeue( &curJob.pid_list ); // Set a local variable for the current command char* curJobCmd = curJob.cmd; // Push the current job to the back of // the job queue push_back_JobDequeue( &jobs, curJob ); // Notify the user that the job has started print_job_bg_start(curJobId, curPID, curJobCmd); }}