From 6a1cae3c869cc6e35b030552cc9954abdbec37c7 Mon Sep 17 00:00:00 2001 From: Amber Date: Sun, 21 Feb 2021 18:11:53 -0500 Subject: [PATCH] Initial commit. --- programming-assignment.c | 186 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 programming-assignment.c diff --git a/programming-assignment.c b/programming-assignment.c new file mode 100644 index 0000000..3a64f36 --- /dev/null +++ b/programming-assignment.c @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************************************************** + * Authors: Gary Fleming, Amber McCloughan + * Class: CIS452 - Operating Systems Concepts + * Professor: Dr. Greg Wolffe + * Date: 1/24/2019 + * + * A simple shell that reads in commands from the user. The user can + * run programs from the shell with a max of 10 arguments. Usage + * statistics are given after a program has finished running in the + * shell. + * + * Type 'quit' to exit the shell. +***************************************************************************/ + +// Number of characters that can be typed when shell is reading input. +#define CHAR_LIMIT 1024 + +// Max number of arguments that can be passed. +#define ARG_LIMIT 32 + +/** + * Clears out arguments from argument buffer for + * after they have been used. + * @param argv, the argument buffer to be cleared. + **/ +void clearArgs(char **argv) +{ + int i; + for (i = 0; i < ARG_LIMIT; i++) + { + argv[i] = NULL; + } +} + +/** + * Main function that drives shell. + **/ +int main() +{ + // The input buffer for reading commands. + char *input = malloc(sizeof(char) * CHAR_LIMIT); + + // The argument buffer for executing programs. + char **argv = malloc(sizeof(char *) * ARG_LIMIT); + + // Counter for parsing arguments, child process status, child process PID. + int count, status, child; + + // Temporary variable for time calculations. + long temp_micro; + + // Struct for gathering usage statistics about child processes. + struct rusage usageStats; + + printf("Welcome! Type \"quit\" to close the shell.\n"); + + /* + * Driving loop of program. + * Inputting 'quit' breaks out of the loop. + */ + while (1) + { + printf("$ "); + + // Reading user input. + input = fgets(input, CHAR_LIMIT, stdin); + + // Handling newline input. + if (!strcmp(input, "\n")) + { + continue; + } + + // Handling loop exit. + if (!strcmp(input, "quit\n")) + { + printf("Goodbye!\n"); + break; + } + + // Removing newlines from end of input. + input = strtok(input, "\n"); + + // Reading first token. + char *token = strtok(input, " "); + + // Setting counter from parsing tokens. + count = 0; + + /* + * Loop for parsing tokens. The following source + * was used to figure out how to properly use + * the strtok() subroutine: + * https://www.geeksforgeeks.org/strtok-strtok_r-functions-c-examples/ + */ + while (token != NULL) + { + // If the counter is at the argument limit, stop. + if (count == ARG_LIMIT) + { + break; + } + + // If a space is entered, replace it with a blank character. + if (!strcmp(token, " ")) + { + argv[count] = ""; + } + // Otherwise, read token into argument buffer. + else + { + argv[count] = token; + } + + // Increment counter. + count++; + + // Onto the next token! + token = strtok(NULL, " "); + } + + // Forking the child process that will exec(). + int pid = fork(); + + // Error handling. + if (pid < 0) + { + printf("Uh-oh. There was an error!\n"); + exit(1); + } + // Child process handling. + else if (pid == 0) + { + // Executing user arguments. + execvp(argv[0], &argv[0]); + + // Handling errors from bad commands. + printf("That didn't work.\n"); + exit(1); + } + // Parent process handling. + else + { + // Waiting on child. Grabs usage stats when waiting finishes. + child = wait3(&status, 0, &usageStats); + + // Clearing argument buffer for next run. + clearArgs(argv); + + // Resetting counter. + count = 0; + + // Don't print usage statistics if child errors. + if (status != 0) + { + continue; + } + + // For user time calculation. + temp_micro = (usageStats.ru_utime.tv_sec * 1000000) + (usageStats.ru_utime.tv_usec); + + // Displaying information to user. + printf("\nChild process with PID %d finished.\n", child); + printf("Child process took %ld microseconds user time.\n", temp_micro); + printf("It also had %ld involuntary context switches.\n", usageStats.ru_nivcsw); + } + + printf("\n"); + } + + // Freeing allocated memory. + free(input); + free(argv); + + // Goodbye. + return 0; +} \ No newline at end of file