Here is a assignment question related to C and operating system. The assignment instruction goes below: 2.1 Part 1A: Do more than 'ls'! Your first
Here is a assignment question related to C and operating system.
The assignment instruction goes below:
2.1 Part 1A: Do more than 'ls'! Your first task is to replace the hard-coded "/bin/ls" call in getCommandFromInput() such that the program can take in user input and run that command instead of "/bin/ls". Your program must be able to handle user input with spaces before and after the command (spaces are ignored).
2.1.1 Prompting and I/O In programming your shell, you will only use system calls and nothing from the C standard library (except string.h). This includes input and output functions like printf(3) and fgets(3). Instead you will use the read(2) and write(2) system calls. Consult the manual pages for these functions' specification. Your shell must prompt the user for input as follows: penn-shredder# Note that the prompt has a white space after the octothorpe, so if a user begins typing, they would see: penn-shredder# somestringhere This part is already in the starter code. Following the prompt, your program will read input from the user. You may assume that the user input will be at most 1024 bytes (including the null-termination byte).
The make file:
# Define variable CC to be the compiler we want to use
CC = clang
# Define CFLAGS for the flags we will want to use with clang
CLANG = -g -Wall
TARGETS = clean penn-shredder
.PHONY: penn-shredder
# If no arguments are passed to make, it will attempt the 'penn-shredder' target
default: penn-shredder
# This runs the 'clean' and 'penn-shredder' targets when 'make all' is run
all: $(TARGETS)
# This will construct the binary 'penn-shredder'
# $^ = names of all the dependent files, deduped and with spaces
# $@ = complete name of the target
penn-shredder: penn-shredder.c
clang -Wall -g $< -o $@
# $(RM) is the platform agnostic way to delete a file (here rm -f)
clean:
$(RM) penn-shredder
The main code:
#include
#include
#include
#include
#include
#include
#include
#define INPUT_SIZE 1024
pid_t childPid = 0;
void executeShell(int timeout);
void writeToStdout(char *text);
void alarmHandler(int sig);
void sigintHandler(int sig);
char *getCommandFromInput();
void registerSignalHandlers();
void killChildProcess();
int main(int argc, char **argv) {
registerSignalHandlers();
int timeout = 0;
if (argc == 2) {
timeout = atoi(argv[1]);
}
if (timeout < 0) {
writeToStdout("Invalid input detected. Ignoring timeout value. ");
timeout = 0;
}
while (1) {
executeShell(timeout);
}
return 0;
}
/* Sends SIGKILL signal to a child process.
* Error checks for kill system call failure and exits program if
* there is an error */
void killChildProcess() {
if (kill(childPid, SIGKILL) == -1) {
perror("Error in kill");
exit(EXIT_FAILURE);
}
}
/* Signal handler for SIGALRM. Catches SIGALRM signal and
* kills the child process if it exists and is still executing.
* It then prints out penn-shredder's catchphrase to standard output */
void alarmHandler(int sig) {
}
/* Signal handler for SIGINT. Catches SIGINT signal (e.g. Ctrl + C) and
* kills the child process if it exists and is executing. Does not
* do anything to the parent process and its execution */
void sigintHandler(int sig) {
if (childPid != 0) {
killChildProcess();
}
}
/* Registers SIGALRM and SIGINT handlers with corresponding functions.
* Error checks for signal system call failure and exits program if
* there is an error */
void registerSignalHandlers() {
if (signal(SIGINT, sigintHandler) == SIG_ERR) {
perror("Error in signal");
exit(EXIT_FAILURE);
}
}
/* Prints the shell prompt and waits for input from user.
* Takes timeout as an argument and starts an alarm of that timeout period
* if there is a valid command. It then creates a child process which
* executes the command with its arguments.
*
* The parent process waits for the child. On unsuccessful completion,
* it exits the shell. */
void executeShell(int timeout) {
char *command;
int status;
char minishell[] = "penn-shredder# ";
writeToStdout(minishell);
command = getCommandFromInput();
if (command != NULL) {
childPid = fork();
if (childPid < 0) {
perror("Error in creating child process");
exit(EXIT_FAILURE);
}
if (childPid == 0) {
char *const envVariables[] = {NULL};
char *const args[] = {command, NULL};
if (execve(command, args, envVariables) == -1) {
perror("Error in execve");
exit(EXIT_FAILURE);
}
} else {
do {
if (wait(&status) == -1) {
perror("Error in child process termination");
exit(EXIT_FAILURE);
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
}
}
/* Writes particular text to standard output */
void writeToStdout(char *text) {
if (write(STDOUT_FILENO, text, strlen(text)) == -1) {
perror("Error in write");
exit(EXIT_FAILURE);
}
}
/* Reads input from standard input till it reaches a new line character.
* Checks if EOF (Ctrl + D) is being read and exits penn-shredder if that is the case
* Otherwise, it checks for a valid input and adds the characters to an input buffer.
*
* From this input buffer, the first 1023 characters (if more than 1023) or the whole
* buffer are assigned to command and returned. An \0 is appended to the command so
* that it is null terminated */
char *getCommandFromInput() {
return "/bin/ls";
}
I will extremely appreciate for your further explanations related to the answer instead of just codes because I can learn from you instead of just copying. Many thanks in advance!
Step by Step Solution
There are 3 Steps involved in it
Step: 1
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started