Skip to content

Instantly share code, notes, and snippets.

@spoonfree
Last active March 3, 2023 04:00
Show Gist options
  • Select an option

  • Save spoonfree/f99ff84bc934b27c6ab768a883a75fd2 to your computer and use it in GitHub Desktop.

Select an option

Save spoonfree/f99ff84bc934b27c6ab768a883a75fd2 to your computer and use it in GitHub Desktop.
assign3.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#define MAX_LINE 102
#define MAX_ARGS 10
int main(int argc, char *argv[]) {
// string to store custom prompt prefix
char *prompt_prefix;
// report error if user specifies too many arguments
if (argc > 2) {
printf("Too many arguments..Only need 1 argument to define custom prompt, otherwise the shell uses > ");
return 1;
} else if (argc == 2) {
// set the custom prefix prompt from the command line argument
prompt_prefix = argv[1];
} else {
// If no value is specified use “> ” as the prompt.
prompt_prefix = ">";
}
// each line of input command should have max size of 102 bytes
char commands[MAX_LINE];
// set max # of arguments per command to be 10
char *args[MAX_ARGS];
// status code for finished process that will be reported later
int status;
while (1) {
// dispay the custom prompt
printf("%s ", prompt_prefix);
// use fgets to accpet the user input and truncate the input at 102 bytes if it exceeds the limit
if (fgets(commands, MAX_LINE, stdin) == NULL) {
// if the shell encounters EOF while reading a line of input, it should exit gracefully without reporting an error.
return 0;
}
// if the user finishes the end of command with a '\n', then change it to file EOF identifier
if (commands[strlen(commands) - 1] == '\n') {
commands[strlen(commands) - 1] = '\0';
}
// If the user entered an empty line, report an error and fetch a new line of input
if (strlen(commands) == 0) {
printf("the user entered an empty input, please provide a valid command\n");
continue;
}
// split the input command i into substrings by delimiter " " and store the substring into args array one by one
char *substrings = strtok(commands, " ");
int i = 0;
while (substrings != NULL) {
args[i] = substrings;
substrings = strtok(NULL, " ");
i++;
}
// append the arguments with NULL pointer to indicate the end of arguments
args[i] = NULL;
// quit our shell to normal shell if user enters "exit"
if (strcmp(args[0], "exit") == 0) {
return 1;
}
// create new child process using fork
pid_t pid = fork();
// handle child process creation failure
if (pid < 0) {
printf("Fork failed. Exiting...\n");
return 1;
}
// pid = 0 means current process is a child process, so we can run the execute file with its arguments using `execvp`
else if (pid == 0) {
// first substring in args is executable file
execvp(args[0], args);
printf("Failed to execute command. Exiting...\n");
return 1;
} else {
// if pid != 0 means current process is a parent process, so we need to wait for the child process to be finished until moving forward
waitpid(pid, &status, 0);
printf("Child process %d exited with status: %d\n", pid, WEXITSTATUS(status));
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment