Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Modify this MP so that you can use \'ls\' instead of \'/bin/ls\' (i.e. the shell

ID: 3802930 • Letter: M

Question

Modify this MP so that you can use 'ls' instead of '/bin/ls' (i.e. the shell searches the path for the command to execute.).

/* LIBRARY SECTION */

#include <ctype.h> /* Character types */

#include <stdio.h> /* Standard buffered input/output */

#include <stdlib.h> /* Standard library functions */

#include <string.h> /* String operations */

#include <sys/types.h> /* Data types */

#include <sys/wait.h> /* Declarations for waiting */

#include <unistd.h> /* Standard symbolic constants and types */

#include <ctype.h> //includes isspace function

#include <sys/stat.h> // mkdir system call per manual

/* DEFINE SECTION */

#define SHELL_BUFFER_SIZE 256 /* Size of the Shell input buffer */

#define SHELL_MAX_ARGS 8 /* Maximum number of arguments parsed */

/* VARIABLE SECTION */

enum { STATE_SPACE, STATE_NON_SPACE };   /* Parser states */

int imthechild(const char *path_to_exec, char *const args[])

{

return execvp(path_to_exec, args) ? -1 : 0;

}

void imtheparent(pid_t child_pid, int run_in_background)

{

int child_return_val;

int child_error_code;

  

/* fork returned a positive pid so we are the parent */

fprintf(stderr,

" Parent says 'child process has been forked with pid=%d' ",

child_pid);

if (run_in_background) {

fprintf(stderr,

" Parent says 'run_in_background=1 ... so we're not waiting for the child' ");

return;

}

wait(&child_return_val);

/* Use the WEXITSTATUS to extract the status code from the return value */

child_error_code = WEXITSTATUS(child_return_val);

fprintf(stderr,

" Parent says 'wait() returned so the child with pid=%d is finished.' ",

child_pid);

if (child_error_code != 0) {

/* Error: Child process failed. Most likely a failed exec */

fprintf(stderr,

" Parent says 'Child process %d failed with code %d' ",

child_pid, child_error_code);

}

}

/* MAIN PROCEDURE SECTION */

int main(int argc, char **argv)

{

pid_t shell_pid;

pid_t pid_from_fork;

size_t n_read;

int i;

int exec_argc = 0;

int parser_state = STATE_SPACE;

int run_in_background;

  

  

/* buffer: The Shell's input buffer. */

char buffer[SHELL_BUFFER_SIZE];

/* exec_argv: Arguments passed to exec call including NULL terminator. */

char *exec_argv[SHELL_MAX_ARGS + 1];

/* Allow the Shell prompt to display the pid of this process */

shell_pid = getpid();

  

while (1) {

/* The Shell runs in an infinite loop, processing input. */

fprintf(stdout, "Shell(pid=%d)> ", shell_pid);

fflush(stdout);

/* Read a line of input. */

scanf("%s", buffer);

  

parser_state = STATE_SPACE;

printf("Enter a line of command, up to 8 words seperated by space: ");

if (fgets(buffer, SHELL_BUFFER_SIZE, stdin) == NULL)

return EXIT_SUCCESS;

n_read = strlen(buffer);

run_in_background = n_read > 2 && buffer[n_read - 2] == '&';

buffer[n_read - run_in_background - 1] = ' ';

  

/* Parse the arguments: the first argument is the file or command *

   * we want to run.

   */

exec_argv[exec_argc] = NULL;

for (exec_argc = 0, i = 0;

   (buffer[i] != ' ') && (exec_argc < SHELL_MAX_ARGS); i++) {

if (!isspace(buffer[i])) {

if (parser_state == STATE_SPACE)

exec_argv[exec_argc++] = &buffer[i];

parser_state = STATE_NON_SPACE;

} else {

buffer[i] = '';

parser_state = STATE_SPACE;

}

}

/* run_in_background is 1 if the input line's last character *

   * is an ampersand (indicating background execution). */

  

buffer[i] = '';   /* Terminate input, overwriting the '&' if it exists */

/* If no command was given (empty line) the Shell just prints the prompt again */

if (!exec_argc)

continue;

/* Terminate the list of exec parameters with NULL */

exec_argv[exec_argc] = NULL;

  

/* If Shell runs 'exit' it exits the program. */

if (!strcmp(exec_argv[0], "exit")) {

printf("Exiting process %d ", shell_pid);

return EXIT_SUCCESS;   /* End Shell program */

  

} else if (!strcmp(exec_argv[0], "cd") && exec_argc > 1) {

/* Running 'cd' changes the Shell's working directory. */

/* Alternative: try chdir inside a forked child: if(fork() == 0) { */

//if (fork() ==0){

if (chdir(exec_argv[1]))

/* Error: change directory failed */

fprintf(stderr, "cd: failed to chdir %s ", exec_argv[1]);

/* End alternative: exit(EXIT_SUCCESS);} */

  

} else {

/* Execute Commands */

/* Try replacing 'fork()' with '0'. What happens? */

//pid_from_fork = fork();

pid_from_fork = 0;

if (pid_from_fork < 0) {

/* Error: fork() failed. Unlikely, but possible (e.g. OS *

   * kernel runs out of memory or process descriptors). */

fprintf(stderr, "fork failed ");

continue;

}

if (pid_from_fork == 0) {

return imthechild(exec_argv[0], &exec_argv[0]);

/* Exit from main. */

} else {

imtheparent(pid_from_fork, run_in_background);

/* Parent will continue around the loop. */

}

} /* end if */

} /* end while loop */

  

return EXIT_SUCCESS;

} /* end main() */

Explanation / Answer

Your Code :

/* LIBRARY SECTION */
#include <ctype.h> /* Character types */
#include <stdio.h> /* Standard buffered input/output */
#include <stdlib.h> /* Standard library functions */
#include <string.h> /* String operations */
#include <sys/types.h> /* Data types */
#include <sys/wait.h> /* Declarations for waiting */
#include <unistd.h> /* Standard symbolic constants and types */
#include <ctype.h> //includes isspace function
#include <sys/stat.h> // mkdir system call per manual

/* DEFINE SECTION */
#define SHELL_BUFFER_SIZE 256 /* Size of the Shell input buffer */
#define SHELL_MAX_ARGS 8 /* Maximum number of arguments parsed */

/* VARIABLE SECTION */
enum { STATE_SPACE, STATE_NON_SPACE }; /* Parser states */


int imthechild(const char *path_to_exec, char *const args[])
{
   return execvp(path_to_exec, args) ? -1 : 0;
}

void imtheparent(pid_t child_pid, int run_in_background)
{
   int child_return_val;
   int child_error_code;

   /* fork returned a positive pid so we are the parent */
   fprintf(stderr,
       " Parent says 'child process has been forked with pid=%d' ",
       child_pid);
   if (run_in_background) {
       fprintf(stderr,
           " Parent says 'run_in_background=1 ... so we're not waiting for the child' ");
       return;
   }
   wait(&child_return_val);
   /* Use the WEXITSTATUS to extract the status code from the return value */
   child_error_code = WEXITSTATUS(child_return_val);
   fprintf(stderr,
       " Parent says 'wait() returned so the child with pid=%d is finished.' ",
       child_pid);
   if (child_error_code != 0) {
       /* Error: Child process failed. Most likely a failed exec */
       fprintf(stderr,
           " Parent says 'Child process %d failed with code %d' ",
           child_pid, child_error_code);
   }
}


/* MAIN PROCEDURE SECTION */
int main(int argc, char **argv)
{
   pid_t shell_pid;
   pid_t pid_from_fork;
   size_t n_read;
   int i;
   int exec_argc = 0;
   int parser_state = STATE_SPACE;
   int run_in_background;


   /* buffer: The Shell's input buffer. */
   char buffer[SHELL_BUFFER_SIZE];
   /* exec_argv: Arguments passed to exec call including NULL terminator. */
   char *exec_argv[SHELL_MAX_ARGS + 1];
   /* Allow the Shell prompt to display the pid of this process */
   shell_pid = getpid();

   while (1) {
       /* The Shell runs in an infinite loop, processing input. */
       fprintf(stdout, "Shell(pid=%d)> ", shell_pid);
       fflush(stdout);
       /* Read a line of input. */
       scanf("%s", buffer);

       parser_state = STATE_SPACE;
       printf("Enter a line of command, up to 8 words seperated by space: ");
       if (fgets(buffer, SHELL_BUFFER_SIZE, stdin) == NULL)
           return EXIT_SUCCESS;
       n_read = strlen(buffer);
       run_in_background = n_read > 2 && buffer[n_read - 2] == '&';
       buffer[n_read - run_in_background - 1] = ' ';

       /* Parse the arguments: the first argument is the file or command *
       * we want to run.
       */
       exec_argv[exec_argc] = NULL;
       for (exec_argc = 0, i = 0;
           (buffer[i] != ' ') && (exec_argc < SHELL_MAX_ARGS); i++) {
           if (!isspace(buffer[i])) {
               if (parser_state == STATE_SPACE)
                   exec_argv[exec_argc++] = &buffer[i];
               parser_state = STATE_NON_SPACE;
           }
           else {
               buffer[i] = '';
               parser_state = STATE_SPACE;
           }
       }
       /* run_in_background is 1 if the input line's last character *
       * is an ampersand (indicating background execution). */

       buffer[i] = ''; /* Terminate input, overwriting the '&' if it exists */
                           /* If no command was given (empty line) the Shell just prints the prompt again */
       if (!exec_argc)
           continue;
       /* Terminate the list of exec parameters with NULL */
       exec_argv[exec_argc] = NULL;

       /* If Shell runs 'exit' it exits the program. */
       if (!strcmp(exec_argv[0], "exit")) {
           printf("Exiting process %d ", shell_pid);
           return EXIT_SUCCESS; /* End Shell program */

       }
       else if (!strcmp(exec_argv[0], "cd") && exec_argc > 1) {
           /* Running 'cd' changes the Shell's working directory. */
           /* Alternative: try chdir inside a forked child: if(fork() == 0) { */
           //if (fork() ==0){
           if (chdir(exec_argv[1]))
               /* Error: change directory failed */
               fprintf(stderr, "cd: failed to chdir %s ", exec_argv[1]);
           /* End alternative: exit(EXIT_SUCCESS);} */

       }
       else {
           /* Execute Commands */
           /* Try replacing 'fork()' with '0'. What happens? */
           //pid_from_fork = fork();
           pid_from_fork = 0;
           if (pid_from_fork < 0) {
               /* Error: fork() failed. Unlikely, but possible (e.g. OS *
               * kernel runs out of memory or process descriptors). */
               fprintf(stderr, "fork failed ");
               continue;
           }
           if (pid_from_fork == 0) {
               return imthechild(exec_argv[0], &exec_argv[0]);
               /* Exit from main. */
           }
           else {
               imtheparent(pid_from_fork, run_in_background);
               /* Parent will continue around the loop. */
           }
       } /* end if */
   } /* end while loop */

   return EXIT_SUCCESS;
} /* end main() */

Modification That Need to be made : You need to call ls like ./ls you have placed your code locally. system by default uses /bin path for looking for the shell command.

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote