Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

Working on a small shell and I'm stuck on this part: Execution If at this point no command word is present, smallsh shall silently return

Working on a small shell and I'm stuck on this part:

Execution

If at this point no command word is present, smallsh shall silently return to step 1 and print a new prompt message. This shall not be an error, and $? shall not be modified.

Built-in commands

If the command to be executed is exit or cd the following built-in procedures shall be executed.

Note: The redirection and background operators mentioned are ignored by built-in commands.

exit

The exit built-in takes one argument. If not provided, the argument is implied to be the expansion of $?, the exit status of the last foreground command.

It shall be an error if more than one argument is provided or if an argument is provided that is not an integer.

Smallsh shall print " exit " to stderr, and then exit with the specified (or implied) value. All child processes in the same process group shall be sent a SIGINT signal before exiting (see KILL(2)). Smallsh does not need to wait on these child processes and may exit immediately.

(See, EXIT(3))

cd

The cd built-in takes one argument. If not provided, the argument is implied to be the expansion of ~/, the value of the HOME environment variable.

If shall be an error if more than one argument is provided.

Smallsh shall change its own current working directory to the specified or implied path. It shall be an error if the operation fails.

(See CHDIR(2))

Here's what I have so far:

#define MAX_ARGS 512

#define MAX_LENGTH 2048

int num_background_pids = 0;

pid_t background_pids[MAX_ARGS];

int status = 0;

bool foreground_only = false;

void error(char* msg) {

fprintf(stderr, "%s ", msg);

status = 1;

}

// CTRL+C

void handle_SIGINT(int signo) {

if (!foreground_only) {

// ignore the signal for background processes

return;

}

// kill the foreground process and set status variable

if (signo == SIGINT) {

fprintf(stderr, "Terminated by signal %d ", signo);

status = 2;

}

}

// CTRL+Z

void handle_SIGTSTP(int signo) {

if (foreground_only) {

// ignore the signal for foreground processes

return;

}

// toggle foreground-only mode and print message

if (signo == SIGTSTP) {

foreground_only = !foreground_only;

if (foreground_only) {

fprintf(stderr, "Entering foreground-only mode (& is now ignored) ");

}

else {

fprintf(stderr, "Exiting foreground-only mode ");

}

}

}

pid_t get_last_background_pid() {

pid_t last_pid = 0;

int i;

for (i = 0; i < num_background_pids; i++) {

int child_status;

pid_t child_pid = waitpid(background_pids[i], &child_status, WNOHANG);

if (child_pid == background_pids[i]) {

if (WIFEXITED(child_status)) {

fprintf(stderr, "Child process %jd done. Exit status %d. ", (intmax_t) child_pid, WEXITSTATUS(child_status));

}

else if (WIFSIGNALED(child_status)) {

fprintf(stderr, "Child process %jd done. Signaled %d. ", (intmax_t) child_pid, WTERMSIG(child_status));

}

else if (WIFSTOPPED(child_status)) {

fprintf(stderr, "Child process %jd stopped. Continuing. ", (intmax_t) child_pid);

kill(child_pid, SIGCONT);

}

background_pids[i] = 0;

}

else {

last_pid = background_pids[i];

}

}

int j = 0;

for (i = 0; i < num_background_pids; i++) {

if (background_pids[i] != 0) {

background_pids[j++] = background_pids[i];

}

}

num_background_pids = j;

return last_pid;

}

int main() {

struct sigaction SIGINT_action = {0};

SIGINT_action.sa_handler = handle_SIGINT;

sigfillset(&SIGINT_action.sa_mask);

SIGINT_action.sa_flags = 0;

sigaction(SIGINT, &SIGINT_action, NULL);

struct sigaction SIGTSTP_action = {0};

SIGTSTP_action.sa_handler = handle_SIGTSTP;

sigfillset(&SIGTSTP_action.sa_mask);

SIGTSTP_action.sa_flags = 0;

sigaction(SIGTSTP, &SIGTSTP_action, NULL);

char *input = NULL;

ssize_t inputSize = 0;

char *delimiters = " \t ";

char *words[MAX_ARGS];

char *prompt = (getenv("PS1") != NULL) ? getenv("PS1") :"";

while(1) {

get_last_background_pid();//before the prompt

printf("%s", prompt);

ssize_t line_length = getline(&input, &inputSize, stdin);

bool input_redir = false, output_redir = false, background = false, comment = false;

int input_pos = -1, output_pos = -1, background_pos = -1, comment_pos = -1;

int i = 0;

words[i] = strtok(input, delimiters);

while (words[i] != NULL) {

if (strcmp(words[i], "<") == 0) {

input_redir = true;

input_pos = i;

}

else if (strcmp(words[i], ">") == 0) {

output_redir = true;

output_pos = i;

}

else if (strcmp(words[i], "&") == 0) {

background = true;

background_pos = i;

}

else if (strcmp(words[i], "#") == 0) {

comment = true;

comment_pos = i;

words[i] = NULL;

break;

}

i++;

words[i] = strtok(NULL, delimiters);

}

if (i > 0) {

if (input_redir && input_pos == i-2) {

freopen(words[i-1], "r", stdin);

words[i-2] = NULL;

}

else if (output_redir && output_pos == i-2) {

freopen(words[i-1], "w", stdout);

words[i-2] = NULL;

}

else if (input_redir && output_redir && (input_pos == i-3 || output_pos == i-3)) {

if (input_pos == i-3) {

freopen(words[i-2], "r", stdin);

words[i-3] = NULL;

}

}

else {

freopen(words[i-2], "w", stdout);

words[i-3] = NULL;

}

}

if (background && background_pos == i-1) {

words[i-1] = NULL;

pid_t pid = fork();

if (pid == 0) {

execvp(words[0], words);

error("Invalid command");

exit(1);

}

else if (pid > 0) {

background_pids[num_background_pids] = pid;

num_background_pids++;

}

else {

error("Fork failed");

}

}

else {

// run in foreground

pid_t pid = fork();

if (pid == 0) {

execvp(words[0], words);

error("Invalid command");

exit(1);

}

else if (pid > 0) {

waitpid(pid, &status, 0);

}

else {

error("Invalid command");

exit(1);

}

}

}

return 0;

}

Thank you!!

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Beginning Databases With PostgreSQL From Novice To Professional

Authors: Richard Stones, Neil Matthew

2nd Edition

1590594789, 978-1590594780

Students also viewed these Databases questions

Question

How do Excel Pivot Tables handle data from non OLAP databases?

Answered: 1 week ago