// This is the shell.c Test: ./shell -test sub #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 "smp1_tests.h" /* Built-in test system */ /* DEFINE SECTION */ #define SHELL_BUFFER_SIZE 256 /* Size of the Shell input buffer */ #define SHELL_MAX_ARGS 8 /* Maximum number of arguments parsed */ #define SHELL_HISTORY_SIZE 10 /* VARIABLE SECTION */ enum { STATE_SPACE, STATE_NON_SPACE }; /* Parser states */ char shell_history[SHELL_HISTORY_SIZE][SHELL_BUFFER_SIZE]; int shell_history_next_index = 0; int imthechild(const char *path_to_exec, char *const args[]) { // TO-DO P5.1 return execvp(path_to_exec, args) ? -1 : 0; } void imtheparent(pid_t child_pid, int run_in_background) { int child_return_val, 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'\n", child_pid); if (run_in_background) { fprintf(stderr, " Parent says 'run_in_background=1 ... so we're not waiting for the child'\n"); return; } // TO-DO P5.4 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.'\n", child_pid); if (child_error_code != 0) { fprintf(stderr, " Parent says 'Child process %d failed with code %d'\n", child_pid, child_error_code); } } int get_shell_command(char *buffer, int size) { int i = 0; char c; while (i < size - 1 && (c = getchar()) != EOF && c != '\n') { buffer[i++] = c; } buffer[i] = '\0'; return i; } void parse_command(char *command, char **exec_args, int *exec_bg) { int argc = 0; *exec_bg = 0; while (*command != '\0') { /* Strip whitespace. */ while (isspace(*command)) { ++command; } if (*command == '\0') { break; } /* Save the argument. */ if (argc < SHELL_MAX_ARGS) { exec_args[argc++] = command; } while (*command != '\0' && !isspace(*command)) { ++command; } if (*command != '\0') { *command++ = '\0'; } } exec_args[argc] = NULL; /* Check for background execution request. */ if (argc > 0 && !strcmp(exec_args[argc - 1], "&")) { *exec_bg = 1; exec_args[--argc] = NULL; } } void run_shell_command; int main(int argc, char **argv) { pid_t shell_pid, pid_from_fork; int n_read, i, exec_argc, parser_state, run_in_background; char buffer[SHELL_BUFFER_SIZE]; char *exec_argv[SHELL_MAX_ARGS + 1]; // TO-DO new variables for P5.2, P5.3, P5.6 if (argc > 1 && !strcmp(argv[1], "-test")) { return run_smp1_tests(argc - 1, argv + 1); } shell_pid = getpid(); int command_counter = 1; while (1) { /* The Shell runs in an infinite loop, processing input. */ if (exec_argc > 0) { command_counter++; } // TO-DO P5.2 .