Question: In C Programming: Stuck on this - Non-Built-in commands Otherwise, the command and its arguments shall be executed in a new child process. If the
In C Programming:
Stuck on this -
Non-Built-in commands
Otherwise, the command and its arguments shall be executed in a new child process. If the command name does not include a /, the command shall be searched for in the systems PATH environment variable (see EXECVP(3)).
If a call to FORK(2) fails, it shall be an error.
In the child:
All signals shall be reset to their original dispositions when smallsh was invoked. Note: This is not the same as SIG_DFL! See oldact in SIGACTION(2).
If a filename was specified as the operand to the input (<) redirection operator, the specified file shall be opened for reading on stdin. It shall be an error if the file cannot be opened for reading or does not already exist.
If a filename was specified as the operand to the output (>) redirection operator, the specified file shall be opened for writing on stdout. If the file does not exist, it shall be created with permissions 0777. It shall be an error if the file cannot be opened (or created) for writing.
If the child process fails to exec (such as if the specified command cannot be found), it shall be an error.
When an error occurs in the child, the child shall immediately print an informative error message to stderr and exit with a non-zero exit status.
#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
Get step-by-step solutions from verified subject matter experts
